home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianFiles.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  126KB  |  4,933 lines

  1. /*ScianFiles.c
  2.   File reading routines for scian
  3.   Eric Pepke
  4.   August 17, 1990
  5.  
  6.   12/4/91    Fixed bug with colored polygons
  7.   12/4/91    Made default file format work on command line
  8. */
  9.  
  10. #include "Scian.h"
  11. #include "ScianTypes.h"
  12. #include "ScianArrays.h"
  13. #include "ScianIcons.h"
  14. #include "ScianWindows.h"
  15. #include "ScianObjWindows.h"
  16. #include "ScianVisWindows.h"
  17. #include "ScianVisObjects.h"
  18. #include "ScianControls.h"
  19. #include "ScianColors.h"
  20. #include "ScianDialogs.h"
  21. #include "ScianFiles.h"
  22. #include "ScianFileSystem.h"
  23. #include "ScianLists.h"
  24. #include "ScianPictures.h"
  25. #include "ScianErrors.h"
  26. #include "ScianTimers.h"
  27. #include "ScianDatasets.h"
  28. #include "ScianFilters.h"
  29. #include "ScianTextBoxes.h"
  30. #include "ScianTitleBoxes.h"
  31. #include "ScianButtons.h"
  32. #include "ScianSliders.h"
  33. #include "ScianScripts.h"
  34. #include "ScianIDs.h"
  35. #include "ScianStyle.h"
  36. #include "ScianMethods.h"
  37. #include "ScianObjFunctions.h"
  38. #include "ScianHwuFiles.h"
  39. #include "ScianSciences.h"
  40. #include "ScianVisObjects.h"
  41. #include "ScianVisSticks.h"
  42. #include "ScianWhisselFiles.h"
  43. #include "ScianAxes.h"
  44. #include "ScianTemplates.h"
  45. #include "ScianTemplateHelper.h"
  46. #include "ScianDatabase.h"
  47. #include "ScianSymbols.h"
  48. #include "ScianSnap.h"
  49. #include "ScianGaryFiles.h"
  50.  
  51. #ifdef HDF31
  52. #define DFSDgetrange DFSDgetmaxmin
  53. #endif
  54.  
  55. char *curFileName = 0;            /*Current file name*/
  56.  
  57. #define SHMDIDDLE            /*Diddle using shared memory technique*/
  58.  
  59. #if 1
  60. #define CARBONALPHA
  61. #endif
  62.  
  63. ObjPtr fileClass;            /*Class of files*/
  64. ObjPtr fileReaderClass;
  65.  
  66. #ifdef SHMDIDDLE
  67. #include <sys/ipc.h>
  68. #include <sys/shm.h>
  69.  
  70. real *sharedSegment = 0;        /*Attached segment*/
  71. #endif
  72.  
  73. #ifdef PROTO
  74. ObjPtr MakeDatasetName(char *);
  75. #else
  76. ObjPtr MakeDatasetName();
  77. #endif
  78.  
  79. void SkipBlanks(file)
  80. FILE *file;
  81. /*Skips blanks in the file*/
  82. {
  83.     int c;
  84.     while ((c = getc(file)) == ' ' || c == '\t');
  85.     ungetc(c, file);
  86. }
  87.  
  88. void SkipBlanksAndCommas(file)
  89. FILE *file;
  90. /*Skips blanks in the file*/
  91. {
  92.     int c;
  93.     while ((c = getc(file)) == ' ' || c == '\t' || c == ',');
  94.     ungetc(c, file);
  95. }
  96.  
  97. void SkipNonBlanks(file)
  98. FILE *file;
  99. /*Skips non-blanks in the file*/
  100. {
  101.     int c;
  102.     while ((c = getc(file)) != ' ' && c >= 0 && c != '\n');
  103.     ungetc(c, file);
  104. }
  105.  
  106. void ReadLn(file)
  107. FILE *file;
  108. /*Reads to next line in the file*/
  109. {
  110.     int c;
  111.     while ((c = getc(file)) >= 0 && c != '\n');
  112. }
  113.  
  114. #ifdef PROTO
  115. void FileFormatError(char *routine, char *what)
  116. #else
  117. void FileFormatError(routine, what)
  118. char *routine, *what;
  119. #endif
  120. /*Reports a file format error*/
  121. {
  122.     ReportError(routine, what);
  123. }
  124.  
  125. char *ShortNameOf(n)
  126. char *n;
  127. /*Returns the short file name of n*/
  128. {
  129.     char *t;
  130.         
  131.     /*Make name last file name in argument*/
  132.     for (t = n; *t; ++t)
  133.     {
  134.     if (*t == '/') n = t + 1;
  135.     }
  136.     return n;
  137. }
  138.  
  139. ObjPtr MakeDatasetName(s)
  140. char *s;
  141. /*Makes and returns a dataset name for file name s*/
  142. {
  143.     Bool hasExtension = false;
  144.     Bool hasNumber = false;
  145.     s = ShortNameOf(s);
  146.     strcpy(tempStr, s);
  147.     s = tempStr;
  148.  
  149.     /*Trim off anything non-numeric after a period*/
  150.     while (*s)
  151.     {
  152.     if (*s == '.')
  153.     {
  154.         hasNumber = true;
  155.     }
  156.     else if (hasNumber)
  157.     {
  158.         if (*s <= '0' || *s >= '9')
  159.         {
  160.         hasNumber = false;
  161.         hasExtension = true;
  162.         }
  163.     }
  164.     ++s;
  165.     }
  166.     if (hasExtension)
  167.     {
  168.     while (*s != '.') --s;
  169.     *s = 0;
  170.     }
  171.     return NewString(tempStr);
  172. }
  173.  
  174. #define ADDCOLORS    100
  175.  
  176. #ifdef PROTO
  177. static VertexPtr ReadNFFVertices(FILE *inFile, int *nVertices)
  178. #else
  179. static VertexPtr ReadNFFVertices(inFile, nVertices)
  180. FILE *inFile;
  181. int *nVertices;
  182. #endif
  183. /*Reads a bunch of NFF vertices from inFile.  Puts the number of vertices in
  184.   nVertices.*/
  185. {
  186.     VertexPtr vertices = 0;
  187.     int nAllocVertices = 0;
  188.     char lookahead;
  189.     float x, y, z, nx, ny, nz;
  190.     int nRead;
  191.     int k;
  192.     real vec1[3], vec2[3];
  193.     real normalLength;
  194.     Bool anyNonZero = false;
  195.  
  196.     *nVertices = 0;
  197.  
  198.     for (;;)
  199.     {
  200.     SkipBlanks(inFile);
  201.     
  202.     lookahead = getc(inFile);
  203.  
  204.     if (lookahead == '#')
  205.     {
  206.         /*It's a comment.  Skip over it*/
  207.         ReadLn(inFile);
  208.     }
  209.     else if (lookahead == '.' || lookahead == '+' || lookahead == '-' || isdigit(lookahead))
  210.     {
  211.         /*It's a possible vertex line*/
  212.         ungetc(lookahead, inFile);
  213.         fgets(tempStr, TEMPSTRSIZE, inFile);
  214.  
  215.         nRead = sscanf(tempStr, " %g %g %g %g %g %g",
  216.         &x, &y, &z, &nx, &ny, &nz);
  217.         if (nRead != 3 && nRead != 6)
  218.         {
  219.         FileFormatError("ReadNFFVertices", "Badly formed vertex");
  220.         continue;
  221.         }
  222.  
  223.         if (*nVertices >= nAllocVertices)
  224.         {
  225.         /*Must reallocate*/
  226.         if (nAllocVertices)
  227.         {
  228.             nAllocVertices += 25;
  229.             vertices = Realloc(vertices, nAllocVertices * sizeof(Vertex));
  230.         }
  231.         else
  232.         {
  233.             nAllocVertices = 25;
  234.             vertices = Alloc(nAllocVertices * sizeof(Vertex));
  235.         }
  236.         }
  237.  
  238.         vertices[*nVertices] . position[0] = x;
  239.         vertices[*nVertices] . position[1] = y;
  240.         vertices[*nVertices] . position[2] = z;
  241.  
  242.         if (nRead == 6)
  243.         {
  244.         vertices[*nVertices] . normal[0] = nx;
  245.         vertices[*nVertices] . normal[1] = ny;
  246.         vertices[*nVertices] . normal[2] = nz;
  247.         }
  248.         else
  249.         {
  250.         vertices[*nVertices] . normal[0] = 0.0;
  251.         vertices[*nVertices] . normal[1] = 0.0;
  252.         vertices[*nVertices] . normal[2] = 0.0;
  253.         }
  254.         ++*nVertices;
  255.     }
  256.     else
  257.     {
  258.         /*End of the vertices*/
  259.         ungetc(lookahead, inFile);
  260.         break;
  261.     }
  262.     }
  263.  
  264.     /*Go through and remake normals, if it's necessary*/
  265.     for (k = 1; k < *nVertices - 1; ++k)
  266.     {
  267.     if (vertices[k] . normal[0] == 0.0 &&
  268.         vertices[k] . normal[1] == 0.0 &&
  269.         vertices[k] . normal[2] == 0.0)
  270.     {
  271.         vec1[0] = vertices[k + 1] . position[0] - vertices[k] . position[0];
  272.         vec1[1] = vertices[k + 1] . position[1] - vertices[k] . position[1];
  273.         vec1[2] = vertices[k + 1] . position[2] - vertices[k] . position[2];
  274.  
  275.         vec2[0] = vertices[k - 1] . position[0] - vertices[k] . position[0];
  276.         vec2[1] = vertices[k - 1] . position[1] - vertices[k] . position[1];
  277.         vec2[2] = vertices[k - 1] . position[2] - vertices[k] . position[2];
  278.  
  279.         CROSS(vec1, vec2, vertices[k] . normal);
  280.         normalLength = sqrt(SQUARE(vertices[k] . normal[0]) +
  281.                 SQUARE(vertices[k] . normal[1]) +
  282.                 SQUARE(vertices[k] . normal[2]));
  283.         if (normalLength > 0.0)
  284.         {
  285.         vertices[k] . normal[0] /= normalLength;
  286.         vertices[k] . normal[1] /= normalLength;
  287.         vertices[k] . normal[2] /= normalLength;
  288.         anyNonZero = true;
  289.         }
  290.     }
  291.     else
  292.     {
  293.         anyNonZero = true;
  294.     }
  295.     }
  296.  
  297.     /*If none nonzero, set the first one arbitrarily*/
  298.     if (!anyNonZero)
  299.     {
  300.     vertices[0] . normal[2] = 1.0;
  301.     }
  302.  
  303.     /*Copy previous nonzero normals going up*/
  304.     for (k = 1; k < *nVertices; ++k)
  305.     {
  306.     if (vertices[k] . normal[0] == 0.0 &&
  307.         vertices[k] . normal[1] == 0.0 &&
  308.         vertices[k] . normal[2] == 0.0)
  309.     {
  310.         vertices[k] . normal[0] = vertices[k - 1] . normal[0];
  311.         vertices[k] . normal[1] = vertices[k - 1] . normal[1];
  312.         vertices[k] . normal[2] = vertices[k - 1] . normal[2];
  313.     }
  314.     }
  315.  
  316.     /*Copy next nonzero normals going down*/
  317.     for (k = (*nVertices) - 2; k >= 0; --k)
  318.     {
  319.     if (vertices[k] . normal[0] == 0.0 &&
  320.         vertices[k] . normal[1] == 0.0 &&
  321.         vertices[k] . normal[2] == 0.0)
  322.     {
  323.         vertices[k] . normal[0] = vertices[k + 1] . normal[0];
  324.         vertices[k] . normal[1] = vertices[k + 1] . normal[1];
  325.         vertices[k] . normal[2] = vertices[k + 1] . normal[2];
  326.     }
  327.     }
  328.     return vertices;
  329. }
  330.  
  331. static ObjPtr ReadNFFXFile(name)
  332. char *name;
  333. /*Reads an extended NFF file from name*/
  334. {
  335.     ObjPtr picture, retVal;
  336.     int c;
  337.     real curTime = 0.0;
  338.     ObjPtr timeSteps = NULLOBJ, timeData = NULLOBJ;
  339.     Bool timeRead = false;
  340.     ObjPtr eternalPicture = NULLOBJ;
  341.     ObjPtr timedObj;
  342.     char cmdStr[256];
  343.     FILE *inFile;
  344.     int whichStep = 0;
  345.     real ox = 0.0, oy = 0.0, oz = 0.0;
  346.     int curColorIndex = -2;
  347.     int nextColorIndex = 2;
  348.     long nColorsAllocated = 0;
  349.     short3 *curColors;
  350.     Bool *colorAllocated;        /*Flag to see if this color is allocated*/
  351.     int k;                /*Counter*/
  352.     int movingStart = -1;        /*Start of moving colors*/
  353.     char *s;                /*String pointer for testing*/
  354.  
  355.     ObjPtr palette;
  356.  
  357.     inFile = fopen(name, "r");
  358.     if (!inFile)
  359.     {
  360.     Error("ReadNFFXFile", OPENFILEERROR, name);
  361.     return NULLOBJ;
  362.     }
  363.  
  364.     nColorsAllocated = ADDCOLORS;
  365.     curColors = (short3 *) Alloc(nColorsAllocated * sizeof(short3));
  366.     curColors[0][0] = 255;
  367.     curColors[0][1] = 255;
  368.     curColors[0][2] = 255;
  369.     curColors[1][0] = 0;
  370.     curColors[1][1] = 0;
  371.     curColors[1][2] = 0;
  372.  
  373.     colorAllocated = (Bool *) Alloc(nColorsAllocated * sizeof(Bool));
  374.     for (k = 0; k < nColorsAllocated; ++k)
  375.     {
  376.     colorAllocated[k] = false;
  377.     }
  378.  
  379.     picture = NewPicture();
  380.  
  381.     /*Read the picture in*/
  382.     for (SkipBlanks(inFile); (c = getc(inFile)) >= 0 && c < 255 && !feof(inFile); SkipBlanks(inFile))
  383.     {
  384.     ungetc(c, inFile);
  385.     fgets(tempStr, 255, inFile);
  386.  
  387.     if (1 == sscanf(tempStr, "%s", cmdStr))
  388.     {
  389.         if (*cmdStr == '#')
  390.         {
  391.         /*It's a comment*/
  392.         }
  393.         else if (0 == strcmp(cmdStr, "t"))
  394.         {
  395.         /*It's a time marker*/
  396.         real nextTime;
  397.         if (1 != sscanf(tempStr, "t %g", &nextTime))
  398.         {
  399.             FileFormatError("ReadNFFXFile", "Bad time step");
  400.             continue;
  401.         }
  402.         if (!timeRead)
  403.         {
  404.            timeRead = true;
  405.            timeSteps = NewList();
  406.            timeData = NewList();
  407.            eternalPicture = picture;
  408.            picture = NewPicture();
  409.         }
  410.         else if (picture)
  411.         {
  412.             /*Got to spit out the old picture*/
  413.             PostfixList(timeSteps, NewReal(curTime));
  414.             PostfixList(timeData, picture);
  415.             picture = NewPicture();
  416.         }
  417.  
  418.         if (movingStart < 0)
  419.         {
  420.             /*First encounter with a time object*/
  421.             movingStart = nextColorIndex;
  422.             if (movingStart < 0) movingStart = 0;
  423.         }
  424.         else
  425.         {
  426.             /*Not first encounter, erase colorAllocated*/
  427.             if (nextColorIndex >= nColorsAllocated - 1)
  428.             {
  429.             nColorsAllocated += ADDCOLORS;
  430.             curColors = (short3 *) Realloc(curColors,
  431.                 nColorsAllocated * sizeof(short3));
  432.             colorAllocated = (Bool *) Realloc(colorAllocated,
  433.                 nColorsAllocated * sizeof(Bool));
  434.             for (k = nextColorIndex; k < nColorsAllocated; ++k)
  435.             {
  436.                 curColors[k][0] = 0;
  437.                 curColors[k][1] = 0;
  438.                 curColors[k][2] = 0;
  439.                 colorAllocated[k] = false;
  440.             }
  441.             }
  442.             for (k = movingStart; k < nextColorIndex; ++k)
  443.             {
  444.             colorAllocated[k] = false;
  445.             }
  446.         }
  447.         curTime = nextTime;
  448.         SkipBlanks(inFile);
  449.         continue;
  450.         }
  451.         else if (0 == strcmp(cmdStr, "f"))
  452.         {
  453.         float r, g, b, d;
  454.         if (8 == sscanf(tempStr, "f %g %g %g %g %g %g %g %g \n",
  455.             &r, &g, &b, &d, &d, &d, &d, &d))
  456.         {
  457.             short rs, gs, bs;
  458.  
  459.             /*It's a valid color.*/
  460.             rs = r * 255.0;
  461.             gs = g * 255.0;
  462.             bs = b * 255.0;
  463.             if (movingStart >= 0)
  464.             {
  465.             /*Already in moving portion.  Search for colors*/
  466.             for (k = movingStart; k < nextColorIndex; ++k)
  467.             {
  468.                 if (!colorAllocated[k] &&
  469.                 curColors[k][0] == rs &&
  470.                 curColors[k][1] == gs &&
  471.                 curColors[k][2] == bs)
  472.                 {
  473.                 curColorIndex = k - 2;
  474.                 colorAllocated[k] = true;
  475.                 goto foundColor;
  476.                 }
  477.             }
  478.             }
  479.  
  480.             if (nextColorIndex >= nColorsAllocated)
  481.             {
  482.             nColorsAllocated += ADDCOLORS;
  483.             curColors = (short3 *) Realloc(curColors,
  484.                 nColorsAllocated * sizeof(short3));
  485.             colorAllocated = (Bool *) Realloc(colorAllocated,
  486.                 nColorsAllocated * sizeof(Bool));
  487.             for (k = nextColorIndex; k < nColorsAllocated; ++k)
  488.             {
  489.                 colorAllocated[k] = false;
  490.             }
  491.             }
  492.             curColorIndex = nextColorIndex - 2;
  493.  
  494.             curColors[nextColorIndex][0] = rs;
  495.             curColors[nextColorIndex][1] = gs;
  496.             curColors[nextColorIndex][2] = bs;
  497.  
  498.             ++nextColorIndex;
  499.         }
  500.         else
  501.         {
  502.             FileFormatError("ReadNFFXFile", "Bad color format statement");
  503.         }
  504. foundColor:;
  505.         }
  506.         else if (0 == strcmp(cmdStr, "s"))
  507.         {
  508.         /*Sphere*/
  509.         float center[3];
  510.         float radius;
  511.         if (4 == sscanf(tempStr, "s %g %g %g %g", 
  512.             &(center[0]), &(center[1]), &(center[2]), &radius))
  513.         {
  514.             center[0] += ox;
  515.             center[1] += oy;
  516.             center[2] += oz;
  517.             
  518.             AppendSphereToPicture(picture, center, radius, curColorIndex);
  519.         }
  520.         else
  521.         {
  522.             FileFormatError("ReadNFFXFile", "Badly formatted sphere");
  523.         }
  524.         }
  525.         else if (0 == strcmp(cmdStr, "o"))
  526.         {
  527.         /*Origin*/
  528.         sscanf(tempStr, "o %g %g %g", &ox, &oy, &oz);
  529.         }
  530.         else if (0 == strcmp(cmdStr, "c"))
  531.         {
  532.         float end1[3], end2[3], rad1, rad2;
  533.         /*It's a conical frustum*/
  534.         if (4 != fscanf(inFile, "%g %g %g %g\n",
  535.             &(end1[0]), &(end1[1]), &(end1[2]), &rad1))
  536.         {
  537.             FileFormatError("ReadNFFXFile", "Badly formed frustum");
  538.             continue;
  539.         }
  540.         end1[0] += ox;
  541.         end1[1] += oy;
  542.         end1[2] += oz;
  543.         if (4 != fscanf(inFile, "%g %g %g %g\n",
  544.             &(end2[0]), &(end2[1]), &(end2[2]), &rad2))
  545.         {
  546.             FileFormatError("ReadNFFXFile", "Badly formed frustum");
  547.             continue;
  548.         }
  549.         end2[0] += ox;
  550.         end2[1] += oy;
  551.         end2[2] += oz;
  552.         AppendFrustumToPicture(picture, end1, rad1, end2, rad2, curColorIndex);
  553.         }
  554.         else if ((0 == strcmp(cmdStr, "p")) ||
  555.              (0 == strcmp(cmdStr, "pp")))
  556.         {
  557.         int nVertices, nReadVertices;
  558.         Vertex *vertices;
  559.         int k;
  560.  
  561.         /*Polygon*/
  562.         s = tempStr;
  563.         SKIPBLANKS(s);
  564.         while (!isspace(*s)) ++s;
  565.         SKIPBLANKS(s);
  566.         if (*s == '*')
  567.         {
  568.             nVertices = -1;
  569.         }
  570.         else
  571.         {
  572.             if (1 != sscanf(s, "%d", &nVertices))
  573.             {
  574.             FileFormatError("ReadNFFFile", "No vertices specified");
  575.             continue;
  576.             }
  577.         }
  578.         
  579.         vertices = ReadNFFVertices(inFile, &nReadVertices);
  580.         if (nVertices > 0 && (nVertices != nReadVertices))
  581.         {
  582.             FileFormatError("ReadNFFFile", "Vertices number mismatch");
  583.         }
  584.         if (vertices)
  585.         {
  586.             for (k = 0; k < nReadVertices; ++k)
  587.             {
  588.             vertices[k] . colorIndex = curColorIndex;
  589.             }
  590.             AppendPolyToPicture(picture, nReadVertices, vertices);
  591.             Free(vertices);
  592.         }
  593.         }
  594.         else if (0 == strcmp(cmdStr, "pl"))
  595.         {
  596.         int nVertices, nReadVertices;
  597.         Vertex *vertices;
  598.         int k;
  599.  
  600.         /*Polyline*/
  601.         s = tempStr;
  602.         SKIPBLANKS(s);
  603.         while (!isspace(*s)) ++s;
  604.         SKIPBLANKS(s);
  605.         if (*s == '*')
  606.         {
  607.             nVertices = -1;
  608.         }
  609.         else
  610.         {
  611.             if (1 != sscanf(s, "%d", &nVertices))
  612.             {
  613.             FileFormatError("ReadNFFFile", "No vertices specified");
  614.             continue;
  615.             }
  616.         }
  617.         
  618.         vertices = ReadNFFVertices(inFile, &nReadVertices);
  619.         if (nVertices > 0 && (nVertices != nReadVertices))
  620.         {
  621.             FileFormatError("ReadNFFFile", "Vertices number mismatch");
  622.         }
  623.         if (vertices)
  624.         {
  625.             for (k = 0; k < nReadVertices; ++k)
  626.             {
  627.             vertices[k] . colorIndex = curColorIndex;
  628.             }
  629.             AppendPolylineToPicture(picture, 1, 0, nReadVertices, vertices);
  630.             Free(vertices);
  631.         }
  632.         }
  633.         else
  634.         {
  635.         char t, err[200];
  636.         t = *tempStr;
  637.         sprintf(err, "Bad object type: %c (%x)", t, t);
  638.         FileFormatError("ReadNFFXFile", err);
  639.         }
  640.     }
  641.     else
  642.     {
  643.         /*Blank line in file*/
  644.     }
  645.     }
  646.  
  647.     /*Now make the object*/
  648.     retVal = NewObject(geometryClass, 0);
  649.     if (picture)
  650.     {
  651.     if (timeRead)
  652.     {
  653.         /*Got to spit out the old picture into the time var*/
  654.         PostfixList(timeSteps, NewReal(curTime));
  655.         PostfixList(timeData, picture);
  656.     }
  657.     else
  658.     {
  659.         /*Just make it eternal*/
  660.         eternalPicture = picture;
  661.     }
  662.     }
  663.  
  664.     if (timeRead)
  665.     {
  666.     timedObj = NewTimedObject(timeSteps, timeData);
  667.     SetVar(retVal, DATA, timedObj);
  668.     SetVar(retVal, ETERNALPART, eternalPicture);
  669.     }
  670.     else
  671.     {
  672.     SetVar(retVal, DATA, eternalPicture);
  673.     }
  674.     SetVar(retVal, NAME, MakeDatasetName(name));
  675.  
  676.     /*Create a new palette*/
  677.     if (nextColorIndex > 2)
  678.     {
  679.     curColors[nextColorIndex][0] = 255;
  680.     curColors[nextColorIndex][1] = 255;
  681.     curColors[nextColorIndex][2] = 255;
  682.     ++nextColorIndex;
  683.     palette = NewPalette(nextColorIndex);
  684.     FieldPaletteName(palette, retVal);
  685.     CopyColorsToPalette(palette, curColors);
  686.     SetVar(retVal, CPALETTE, palette);
  687.     SetVar(retVal, COLORBYSELF, ObjTrue);
  688.     }
  689.     Free(curColors);
  690.     Free(colorAllocated);
  691.  
  692.     fclose(inFile);
  693.     RegisterDataset(retVal);
  694.     return NULLOBJ;
  695. }
  696.  
  697. static ObjPtr ReadJAKFile(name)
  698. char *name;
  699. /*Reads one of jayakumar's files*/
  700. {
  701.     ObjPtr timeSteps, timeData;
  702.     ObjPtr timedObj;
  703.     FILE *inFile;
  704.     int whichFrame;
  705.     real dims[2];            /*The dimensions of the data, temp.*/
  706.     real bounds[6];            /*The bounds of the data form*/
  707.     long xSize, ySize;
  708.     real dataMin, dataMax;
  709.     real tempMin, tempMax;
  710.     ObjPtr dataForm;
  711.     ObjPtr dimsArray, boundsArray;
  712.     ObjPtr retVal;
  713.  
  714.     inFile = fopen(name, "r");
  715.     if (!inFile)
  716.     {
  717.     Error("ReadJAKFile", OPENFILEERROR, name);
  718.     return NULLOBJ;
  719.     }
  720.  
  721.     timeSteps = NewList();
  722.     timeData = NewList();
  723.  
  724.     /*Read in the frames*/
  725.     whichFrame = 0;
  726.     while (fscanf(inFile, " %ld %ld", &xSize, &ySize) == 2)
  727.     {
  728.     ObjPtr data;
  729.     int i, j;
  730.     real *dataPtr;
  731.  
  732.     if (fscanf(inFile, " %g %g", &tempMin, &tempMax) != 2)
  733.     {
  734.         char err[200];
  735.         sprintf(err, "Error reading minmax in frame %d", whichFrame);
  736.         FileFormatError("ReadJAKFile", err);
  737.         fclose(inFile);
  738.         return NULLOBJ;
  739.     }
  740.  
  741.     if (whichFrame == 0)
  742.     {
  743.         /*If it's the first frame, set sizes and minmax*/
  744.         dims[0] = xSize;
  745.         dims[1] = ySize;
  746.         dataMin = tempMin;
  747.         dataMax = tempMax;
  748.     }
  749.     else
  750.     {
  751.         /*Enlarge minmax*/
  752.         if (tempMin < dataMin) dataMin = tempMin;
  753.         if (tempMax > dataMax) dataMax = tempMax;
  754.     }
  755.  
  756.     data = NewRealArray(2, xSize, ySize);
  757.     dataPtr = ArrayMeat(data) + (ySize - 1) * xSize;
  758.     for (j = 0; j < ySize; ++j)
  759.     {
  760.         for (i = 0; i < xSize; ++i)
  761.         {
  762.         if (1 != fscanf(inFile, " %g", dataPtr))
  763.         {
  764.             char err[200];
  765.             sprintf(err, "Error in frame %d at %d %d", whichFrame, i, j);
  766.             FileFormatError("ReadJAKFile", err);
  767.             fclose(inFile);
  768.             return NULLOBJ;
  769.         }
  770.         ++dataPtr;
  771.         }
  772.         dataPtr -= 2 * xSize;
  773.     }
  774.     PostfixList(timeSteps, NewReal((real) whichFrame));
  775.     PostfixList(timeData, data);
  776.     ++whichFrame;
  777.     }
  778.  
  779.     fclose(inFile);
  780.  
  781.     /*Create the data form*/
  782.     dataForm = NewObject(dataFormClass, 0);
  783.     dimsArray = NewRealArray(1, (long) 2);
  784.     
  785.     /*Put in some dimensions*/
  786.     CArray2Array(dimsArray, dims);
  787.     SetVar(dataForm, DIMENSIONS, dimsArray); 
  788.  
  789.     /*Put in the bounds*/
  790.     bounds[0] = 0.;
  791.     bounds[1] = 1000.0;
  792.     bounds[2] = 0.;
  793.     bounds[3] = 1000.0;
  794.     bounds[4] = dataMin;
  795.     bounds[5] = dataMax;
  796.     boundsArray = NewRealArray(1, (long) 6);
  797.     CArray2Array(boundsArray, bounds);
  798.     SetVar(dataForm, BOUNDS, boundsArray);
  799.  
  800.     /*Create the field*/
  801.     retVal = NewObject(data2DScalar, 0);
  802.     SetVar(retVal, DATA, NewTimedObject(timeSteps, timeData));
  803.     SetVar(retVal, DATAFORM, dataForm);
  804.     SetVar(retVal, NAME, MakeDatasetName(name));
  805.  
  806.     RegisterDataset(retVal);
  807.     return NULLOBJ;
  808. }
  809.  
  810. #define DS(k) \
  811.     if (1 != fread(&dataSize, sizeof(long), 1, inFile) ||        \
  812.     dataSize != k)                            \
  813.     {                                    \
  814.     FileFormatError("ReadJAKFile", "Data length error");         \
  815.     fclose(inFile);                            \
  816.     return NULLOBJ;                            \
  817.     }
  818.  
  819.  
  820. static ObjPtr ReadJAKBFile(name)
  821. char *name;
  822. /*Reads one of jay a kumar's binary files*/
  823. {
  824.     ObjPtr timeSteps, timeData;
  825.     ObjPtr timedObj;
  826.     FILE *inFile;
  827.     long whichFrame;
  828.     real dims[2];            /*The dimensions of the data, temp.*/
  829.     real bounds[6];            /*The bounds of the data form*/
  830.     long xSize, ySize;
  831.     long dataSize;            /*Dummy to hold size of data*/
  832.     real dataMin, dataMax;
  833.     ObjPtr dataForm;
  834.     ObjPtr dimsArray, boundsArray;
  835.     ObjPtr retVal;
  836.     long nFrames;
  837.  
  838.     inFile = fopen(name, "r");
  839.     if (!inFile)
  840.     {
  841.     Error("ReadJAKFile", OPENFILEERROR, name);
  842.     return NULLOBJ;
  843.     }
  844.  
  845.     timeSteps = NewList();
  846.     timeData = NewList();
  847.  
  848.     whichFrame = 0;
  849.  
  850.     DS(4);
  851.     if (1 != fread(&nFrames, sizeof(int), 1, inFile))
  852.     {
  853.     FileFormatError("ReadJAKFile", "Error reading nframes");
  854.     fclose(inFile);
  855.     return NULLOBJ;
  856.     }
  857.     DS(4);
  858.  
  859.     DS(8);
  860.     if (1 != fread(&xSize, sizeof(int), 1, inFile))
  861.     {
  862.     FileFormatError("ReadJAKFile", "Error reading size");
  863.     fclose(inFile);
  864.     return NULLOBJ;
  865.     }
  866.     if (1 != fread(&ySize, sizeof(int), 1, inFile))
  867.     {
  868.     FileFormatError("ReadJAKFile", "Error reading size");
  869.     fclose(inFile);
  870.     return NULLOBJ;
  871.     }
  872.     DS(8);
  873.     dims[0] = xSize;
  874.     dims[1] = ySize;
  875.  
  876.     DS(8);
  877.     if (1 != fread(&dataMin, sizeof(real), 1, inFile))
  878.     {
  879.     FileFormatError("ReadJAKFile", "Error reading size");
  880.     fclose(inFile);
  881.     return NULLOBJ;
  882.     }
  883.     if (1 != fread(&dataMax, sizeof(real), 1, inFile))
  884.     {
  885.     FileFormatError("ReadJAKFile", "Error reading size");
  886.     fclose(inFile);
  887.     return NULLOBJ;
  888.     }
  889.     DS(8);
  890.  
  891.     FileFormatError("ReadJAKFile", "Error reading size");
  892.  
  893.     /*Read in the frames*/
  894.  
  895.     while (1 == fread(&dataSize, sizeof(long), 1, inFile))    
  896.     {
  897.     ObjPtr data;
  898.     int i, j;
  899.     real *dataPtr;
  900.  
  901.     if (dataSize != 4)
  902.     {
  903.         FileFormatError("ReadJAKFile", "Data length error"); 
  904.         fclose(inFile);
  905.         return NULLOBJ;
  906.     }
  907.     if (1 != fread(&whichFrame, sizeof(long), 1, inFile))
  908.     {
  909.         char err[256];
  910.         sprintf(err, "Error reading frame #\n");
  911.         FileFormatError("ReadJAKFile", err);
  912.         fclose(inFile);
  913.         return NULLOBJ;
  914.     }
  915.     DS(4);
  916.  
  917.     data = NewRealArray(2, xSize, ySize);
  918.     dataPtr = ArrayMeat(data) + (ySize - 1) * xSize;
  919.     for (j = 0; j < ySize; ++j)
  920.     {
  921.         DS(xSize * sizeof(real));
  922.         if (xSize != fread(dataPtr, sizeof(real), xSize, inFile))
  923.         {
  924.         char err[200];
  925.         sprintf(err, "Error reading frame %d", whichFrame);
  926.         FileFormatError("ReadJAKBFile", err);
  927.         fclose(inFile);
  928.         return NULLOBJ;
  929.         }
  930.  
  931.         DS(xSize * sizeof(real));
  932.         dataPtr -= xSize;
  933.     }
  934.     PostfixList(timeSteps, NewReal((real) whichFrame));
  935.     PostfixList(timeData, data);
  936.     }
  937.     fclose(inFile);
  938.  
  939.     /*Create the data form*/
  940.     dataForm = NewObject(dataFormClass, 0);
  941.     dimsArray = NewRealArray(1, (long) 2);
  942.     
  943.     /*Put in some dimensions*/
  944.     CArray2Array(dimsArray, dims);
  945.     SetVar(dataForm, DIMENSIONS, dimsArray); 
  946.  
  947.     /*Put in the bounds*/
  948.     bounds[0] = 0.;
  949.     bounds[1] = 1000.0;
  950.     bounds[2] = 0.;
  951.     bounds[3] = 1000.0;
  952.     bounds[4] = dataMin;
  953.     bounds[5] = dataMax;
  954.     boundsArray = NewRealArray(1, (long) 6);
  955.     CArray2Array(boundsArray, bounds);
  956.     SetVar(dataForm, BOUNDS, boundsArray);
  957.  
  958.     /*Create the field*/
  959.     retVal = NewObject(data2DScalar, 0);
  960.  
  961.     SetVar(retVal, DATA, NewTimedObject(timeSteps, timeData));
  962.     {
  963.     ObjPtr minMaxArray;
  964.     real minMax[2];
  965.     minMax[0] = dataMin;
  966.     minMax[1] = dataMax;
  967.                 minMaxArray = NewRealArray(1, 2L);
  968.                     CArray2Array(minMaxArray, minMax);
  969.                     SetVar(retVal, MINMAX, minMaxArray);
  970.     }
  971.     SetVar(retVal, DATAFORM, dataForm);
  972.     SetVar(retVal, NAME, MakeDatasetName(name));
  973.  
  974.     RegisterDataset(retVal);
  975.     return NULLOBJ;
  976. }
  977.  
  978. static ObjPtr ReadSYFile(name)
  979. char *name;
  980. /*Reads one of Saul Youssef's fields from file name*/
  981. {
  982.     float dx, dy, dz;
  983.     int lx, ly, lz;
  984.     float minX, minY, minZ;
  985.     float maxX, maxY, maxZ;
  986.     ObjPtr dataForm;            /*The grid holding the data*/
  987.     ObjPtr boundsArray;            /*Array containing bounds of grid*/
  988.     ObjPtr dimsArray;            /*Array containing dimensions*/
  989.     ObjPtr fieldData;            /*The array of data in the field*/
  990.     real dims[3];            /*The dimensions of the data, temp.*/
  991.     real bounds[6];            /*The bounds of the data form*/
  992.     real *dataPtr;            /*The meat of the array*/
  993.     int i, j, k;            /*Index into the grid*/
  994.     ObjPtr retVal;            /*The field to return*/
  995.     FILE *inFile;
  996.  
  997.     inFile = fopen(name, "r");
  998.     if (!inFile)
  999.     {
  1000.     Error("ReadSYFile", OPENFILEERROR, name);
  1001.     return NULLOBJ;
  1002.     }
  1003.  
  1004.     /*Read header*/
  1005.     if (fscanf(inFile, " %d %d %d %g %g %g %g %g %g",
  1006.         &lx, &ly, &lz, &minX, &maxX, &minY, &maxY, &minZ, &maxZ)
  1007.     != 9) 
  1008.     {
  1009.     FileFormatError("ReadSYFile", "Error reading header");
  1010.     }
  1011.  
  1012.     /*Create the data form*/
  1013.     dataForm = NewObject(dataFormClass, 0);
  1014.     dimsArray = NewRealArray(1, (long) 3);
  1015.     
  1016.     /*Put in some dimensions*/
  1017.     dims[0] = (real) lx;
  1018.     dims[1] = (real) ly;
  1019.     dims[2] = (real) lz;
  1020.     CArray2Array(dimsArray, dims);
  1021.     SetVar(dataForm, DIMENSIONS, dimsArray); 
  1022.  
  1023.     /*Put in the bounds*/
  1024.     bounds[0] = minX;
  1025.     bounds[1] = maxX;
  1026.     bounds[2] = minY;
  1027.     bounds[3] = maxY;
  1028.     bounds[4] = minZ;
  1029.     bounds[5] = maxZ;
  1030.     boundsArray = NewRealArray(1, (long) 6);
  1031.     CArray2Array(boundsArray, bounds);
  1032.     SetVar(dataForm, BOUNDS, boundsArray);
  1033.  
  1034.     /*Read the data*/
  1035.     fieldData = NewRealArray(3, (long) lx, (long) ly, (long) lz);
  1036.     dataPtr = ArrayMeat(fieldData);
  1037.  
  1038.     for (k = 0; k < lz; ++k)
  1039.     {
  1040.     for (j = 0; j < ly; ++j)
  1041.     {
  1042.         for (i = 0; i < lx; ++i)
  1043.         {
  1044.         real curVal;
  1045.         if (1 != fscanf(inFile, " %g", &curVal))
  1046.         {
  1047.             FileFormatError("ReadSYFile", "Error reading data");
  1048.             fclose(inFile);
  1049.             return NULLOBJ;
  1050.         }
  1051.         *(dataPtr + i * ly * lz + j * lz + k) = curVal;
  1052.         }
  1053.     }
  1054.     }
  1055.  
  1056.     /*Create the field*/
  1057.     retVal = NewObject(data3DScalar, 0);
  1058.     SetVar(retVal, DATA, fieldData);
  1059.     SetVar(retVal, DATAFORM, dataForm);
  1060.     SetVar(retVal, NAME, MakeDatasetName(name));
  1061.  
  1062.     fclose(inFile);
  1063.     RegisterDataset(retVal);
  1064.     return NULLOBJ;
  1065. }
  1066.  
  1067. #ifdef LORENZ
  1068. #define LRZNMAX 10
  1069.  
  1070. #ifdef FORTRAN_
  1071. extern void odeint_();
  1072. #else
  1073. extern void odeint();
  1074. #endif
  1075.  
  1076. static ObjPtr ReadLRZFile(name)
  1077. char *name;
  1078. /*Reads a Lorenz attractor initial value file*/
  1079. {
  1080.     float y[LRZNMAX];        /*3 initial values*/
  1081.     float dydx[LRZNMAX];
  1082.     int nstep, nskip;
  1083.     int nvar;
  1084.     float xstart;
  1085.     float eps, stpmin, stpsize, sig, b, r;
  1086.     real *dataPtr;
  1087.     ObjPtr theData, theClass, lrzObj;
  1088.     FILE *inFile;
  1089.  
  1090.     inFile = fopen(name, "r");
  1091.     if (!inFile)
  1092.     {
  1093.     Error("ReadLRZFile", OPENFILEERROR, name);
  1094.     return NULLOBJ;
  1095.     }
  1096.  
  1097.     /*Read the file*/
  1098.     if (11 != fscanf(inFile, " %f %f %f %f %d %d %f %f %f %f %f",
  1099.         &(y[0]), &(y[1]), &(y[2]), &stpsize, &nstep,
  1100.         &nskip, &eps, &stpmin, &sig, &b, &r))
  1101.     {
  1102.     FileFormatError("ReadLRZFile", "Cannot read parameter file");
  1103.     fclose(inFile);
  1104.     return NULLOBJ;
  1105.     }
  1106.  
  1107.     /*Now we know how big it is, make some data*/
  1108.     theData = NewRealArray(2, (long) nstep, (long) LRZNMAX);
  1109.     if (!theData)
  1110.     {
  1111.     fclose(inFile);
  1112.         return NULLOBJ;
  1113.     }
  1114.     dataPtr = ArrayMeat(theData);
  1115.  
  1116.     nvar = 3;
  1117.     xstart = 0.0;
  1118. #ifdef FORTRAN_ 
  1119.     odeint_
  1120. #else
  1121.     odeint
  1122. #endif
  1123.     (y, &nvar, &xstart, &nskip, &nstep, dataPtr,
  1124.         &eps, &stpsize, &stpmin, &sig, &b, &r);
  1125.  
  1126.     /*Now create the data object*/
  1127.     theClass = NewObject(data1DVector, 0);
  1128.     lrzObj = NewObject(theClass, 0);
  1129.     SetVar(lrzObj, DATA, theData);
  1130.     SetVar(lrzObj, NAME, MakeDatasetName(name));
  1131.  
  1132.     fclose(inFile);
  1133.     RegisterDataset(lrzObj);
  1134.     return NULLOBJ;
  1135. }
  1136. #endif
  1137.  
  1138. static ObjPtr ReadDDFile(name)
  1139. char *name;
  1140. /*Reads a Dennis Duke format file*/
  1141. {
  1142.     long idim, jdim;
  1143.     int c, k;
  1144.     ObjPtr theData, theClass, eegData;
  1145.     FILE *inFile;
  1146.     long index[1];
  1147.  
  1148.     inFile = fopen(name, "r");
  1149.     if (!inFile)
  1150.     {
  1151.     Error("ReadDDFile", OPENFILEERROR, name);
  1152.     return NULLOBJ;
  1153.     }
  1154.  
  1155.     /*First determine idim and jdim*/
  1156.     idim = 0; jdim = 0;
  1157.  
  1158.     SkipBlanks(inFile);
  1159.     while ((c = getc(inFile)) >= 0)
  1160.     {
  1161.         ungetc(c, inFile);
  1162.         ++jdim;
  1163.         k = 0;
  1164.         while ((c = getc(inFile)) >= 0 && c != '\n')
  1165.         {
  1166.             ungetc(c, inFile);
  1167.             SkipNonBlanks(inFile);
  1168.             SkipBlanks(inFile);
  1169.             ++k;
  1170.         }
  1171.         if (idim > 0)
  1172.         {
  1173.             if (k != idim)
  1174.             {
  1175.         char err[200];
  1176.                 sprintf(err,
  1177.                     "Error in %s line %d: bad number of items\n",
  1178.                     name, jdim);
  1179.         FileFormatError("ReadDDFile", err);
  1180.         fclose(inFile);
  1181.         return NULLOBJ;
  1182.             }
  1183.             else
  1184.             {
  1185.                 idim = k;
  1186.             }
  1187.         }
  1188.         else
  1189.         {
  1190.             idim = k;
  1191.         }
  1192.         getc(inFile);
  1193.         SkipBlanks(inFile);
  1194.     }
  1195.  
  1196.     /*Now we know how big it is, make some data*/
  1197.     theData = NewArray(AT_OBJECT, 1, &idim);
  1198.     for (k = 0; k < idim; ++k)
  1199.     {
  1200.     ((ObjPtr *) ELEMENTS(theData))[k] = NewRealArray(1, (long) jdim);
  1201.     }
  1202.  
  1203.     /*Now create the data object*/
  1204.     theClass = NewObject(data1DVector, 0);
  1205.     eegData = NewObject(theClass, 0);
  1206.     SetVar(eegData, DATA, theData);
  1207.     SetVar(eegData, NAME, MakeDatasetName(name));
  1208.  
  1209.     if (!SetCurField(FIELD1, eegData)) return NULLOBJ;
  1210.  
  1211.     /*Read in the data*/
  1212.     rewind(inFile);
  1213.     SkipBlanks(inFile);
  1214.  
  1215.     index[0] = 0;
  1216.     while ((c = getc(inFile)) >= 0)
  1217.     {
  1218.         ungetc(c, inFile);
  1219.         k = 0;
  1220.         while ((c = getc(inFile)) >= 0 && c != '\n')
  1221.         {
  1222.         real data;
  1223.             ungetc(c, inFile);
  1224.             if (1 != fscanf(inFile, "%g", &data))
  1225.         {
  1226.         FileFormatError("ReadDDFile", "Bad number");
  1227.         fclose(inFile);
  1228.         return NULLOBJ;
  1229.         }
  1230.         PutFieldComponent(FIELD1, k, index, data);
  1231.  
  1232.         ++k;
  1233.         if (k >= idim)
  1234.         {
  1235.         k = 0;
  1236.         ++index[0];
  1237.         }
  1238.             SkipBlanksAndCommas(inFile);
  1239.         }
  1240.         getc(inFile);
  1241.         SkipBlanksAndCommas(inFile);
  1242.     }
  1243.  
  1244.     fclose(inFile);
  1245.     SetVar(eegData, NCOMPONENTS, NewInt(idim));
  1246.     RegisterDataset(eegData);
  1247.     return NULLOBJ;
  1248. }
  1249.  
  1250. static ObjPtr brainForm = 0;
  1251. long numNodes;             /*Number of nodes in brain form*/
  1252.  
  1253. /*States for data form reading machine*/
  1254. #define S_READNODES    1
  1255. #define S_READEDGES    2
  1256. #define S_READCELLS    3
  1257. #define S_READPOLATIONS 4
  1258.  
  1259. #define DD2SECS        8.0
  1260. #define DD2SAMPLES    1024
  1261. #define DD2POINTS    19
  1262.  
  1263. #define NPOLATIONS    100
  1264. int pDerived[NPOLATIONS];
  1265. int pNear[NPOLATIONS];
  1266. int pFar[NPOLATIONS];
  1267. real pFac[NPOLATIONS];
  1268. int nPolations = 0;
  1269.  
  1270. static ObjPtr ReadDD2File(name)
  1271. char *name;
  1272. /*Reads a brain surface EEG file*/
  1273. {
  1274.     ObjPtr retVal;
  1275.     ObjPtr timeSteps;
  1276.     ObjPtr timeData;
  1277.     FILE *inFile;
  1278.     int sample;
  1279.     long k;
  1280.     real *data, dummy;
  1281.     real minMax[2];
  1282.     ObjPtr minMaxArray;
  1283.  
  1284.     if (!brainForm)
  1285.     {
  1286.     /*Must make the brain data form*/
  1287.     threeArray *nodeBuf;
  1288.     long nodeBufSize;
  1289.     TwoReals *edgeBuf;
  1290.     long edgeBufSize;
  1291.     long numEdges;
  1292.     long numCells;
  1293.     ObjPtr cellList;
  1294.     ObjPtr nodeData;
  1295.     ObjPtr edgeArray;
  1296.     int state;
  1297.     char line[257];
  1298.     char token[257];
  1299.     char *s;
  1300.     real val;
  1301.     int lineNum;
  1302.     char pTypeChar;
  1303.     long tempDims[3];
  1304.     real bounds[6];
  1305.  
  1306.     /*Open the file*/
  1307.     lineNum = 0;
  1308.     state = 0;
  1309.     inFile = fopen("brainform", "r");
  1310.     if (!inFile)
  1311.     {
  1312.         FileFormatError("ReadDD2File", "File brainform was not found");
  1313.         return NULLOBJ;
  1314.     }
  1315.  
  1316.     /*Create the buffers.  First the nodes*/
  1317.     numNodes = 0;
  1318.     nodeBufSize = 1000;
  1319.     nodeBuf = (threeArray *) Alloc(nodeBufSize * 3 * sizeof(real));
  1320.     if (!nodeBuf)
  1321.     {
  1322.         OMErr();
  1323.         return NULLOBJ;
  1324.     }
  1325.  
  1326.     /*Then the edges*/
  1327.     numEdges = 0;
  1328.     edgeBufSize = 1000;
  1329.     edgeBuf = (TwoReals *) Alloc(edgeBufSize * 2 * sizeof(real));
  1330.     if (!edgeBuf)
  1331.     {
  1332.         OMErr();
  1333.         Free(nodeBuf);
  1334.         return NULLOBJ;
  1335.     }
  1336.  
  1337.     /*Now the cells*/
  1338.     numCells = 0;
  1339.     cellList = NewList();
  1340.     if (!cellList)
  1341.     {
  1342.         Free(edgeBuf);
  1343.         Free(nodeBuf);
  1344.         return NULLOBJ;
  1345.     }
  1346.     
  1347.     /*Now read the file*/
  1348.     while (++lineNum, fgets(line, 256, inFile))
  1349.     {
  1350.         s = &(line[0]);
  1351.  
  1352.         /*Get the first token*/
  1353.         SHIFTNUM(token, s);
  1354.         if (0 == strcmp2(token, "NODES"))
  1355.         {
  1356.         state = S_READNODES;
  1357.         }
  1358.         else if (0 == strcmp2(token, "EDGES"))
  1359.         {
  1360.         state = S_READEDGES;
  1361.         }
  1362.         else if (0 == strcmp2(token, "CELLS"))
  1363.         {
  1364.         state = S_READCELLS;
  1365.         }
  1366.         else if (0 == strcmp2(token, "POLATIONS"))
  1367.         {
  1368.         state = S_READPOLATIONS;
  1369.         }
  1370.         else if (1 == sscanf(token, "%g", &val))
  1371.         {
  1372.         /*It's a number.  Do something based on the state*/
  1373.         switch(state)
  1374.         {
  1375.             case S_READNODES:
  1376.             /*It must be the x of a node*/
  1377.             {
  1378.                 real x, y, z;
  1379.                 if (numNodes > nodeBufSize)
  1380.                 {
  1381.                 /*Must expand the node buffer*/    
  1382.                 nodeBufSize += 200;    
  1383.                 nodeBuf = (threeArray *) Realloc(nodeBuf, nodeBufSize * sizeof(threeArray));
  1384.                 if (!nodeBuf)
  1385.                 {
  1386.                     OMErr();    
  1387.                     Free(edgeBuf);
  1388.                     return NULLOBJ;
  1389.                 }
  1390.                 }
  1391.                 x = val;
  1392.                 SHIFTNUM(token, s);
  1393.                 if (1 != sscanf(token, "%g", &y))
  1394.                 {
  1395.                 char err[200];
  1396.                 sprintf(err, "Error in line %d of brainform: Missing y\n", lineNum);
  1397.                 FileFormatError("ReadDD2File", err);
  1398.                 break;
  1399.                 }
  1400.                 SHIFTNUM(token, s);
  1401.                 if (1 != sscanf(token, "%g", &z))
  1402.                 {
  1403.                 char err[200];
  1404.                 sprintf(err, "Error in line %d of brainform: Missing z\n", lineNum);
  1405.                 FileFormatError("ReadDD2File", err);
  1406.                 break;
  1407.                 }
  1408.                 nodeBuf[numNodes][0] = x;
  1409.                 nodeBuf[numNodes][1] = y;
  1410.                 nodeBuf[numNodes][2] = z;
  1411.                 ++numNodes;
  1412.             }
  1413.             break;
  1414.             case S_READEDGES:
  1415.             /*It must be the first node of an edge*/
  1416.             {
  1417.                 real n1, n2;
  1418.                 if (numEdges > edgeBufSize)
  1419.                 {
  1420.                 /*Must expand the node buffer*/    
  1421.                 edgeBufSize += 200;    
  1422.                 edgeBuf = (TwoReals *) Realloc(edgeBuf, edgeBufSize * sizeof(TwoReals));
  1423.                 if (!nodeBuf)
  1424.                 {
  1425.                     OMErr();    
  1426.                     Free(nodeBuf);
  1427.                     return NULLOBJ;
  1428.                 }
  1429.                 }
  1430.                 n1 = val;
  1431.                 SHIFTNUM(token, s);
  1432.                 if (1 != sscanf(token, "%g", &n2))
  1433.                 {
  1434.                 char err[200];
  1435.                 sprintf(err, "Error in line %d of brainform: Missing second node\n", lineNum);
  1436.                 FileFormatError("ReadDD2File", err);
  1437.                 break;
  1438.                 }
  1439.                 edgeBuf[numEdges][0] = n1;
  1440.                 edgeBuf[numEdges][1] = n2;
  1441.                 ++numEdges;
  1442.             }
  1443.             break;
  1444.             case S_READCELLS:
  1445.             /*It must be the first node of a cell*/
  1446.             {
  1447.                 real cellBuf[600];
  1448.                 ObjPtr cellArray;
  1449.                 long c;
  1450.                 c = 0;
  1451.                 do
  1452.                 {
  1453.                 cellBuf[c++] = val;
  1454.                 SHIFTNUM(token, s);
  1455.                 } while (1 == sscanf(token, "%g", &val)); 
  1456.                 cellArray = NewRealArray(1, c);
  1457.                 CArray2Array(cellArray, cellBuf);
  1458.                 PostfixList(cellList, cellArray);
  1459.                 ++numCells;
  1460.             }
  1461.             break;
  1462.             default:
  1463.             FileFormatError("ReadDD2File", "Error in brainform");
  1464.         }
  1465.         }
  1466.         else if (1 == sscanf(token, "%c", &pTypeChar))
  1467.         {
  1468.         switch (state)
  1469.         {
  1470.             case S_READPOLATIONS:
  1471.             SHIFTNUM(token, s);
  1472.              if (1 != sscanf(token, "%d", &(pDerived[nPolations])))
  1473.             {
  1474.                 FileFormatError("ReadDD2File", "Error in brainform");
  1475.                 break;
  1476.             }
  1477.             SHIFTNUM(token, s);
  1478.              if (1 != sscanf(token, "%d", &(pNear[nPolations])))
  1479.             {
  1480.                 FileFormatError("ReadDD2File", "Error in brainform");
  1481.                 break;
  1482.             }
  1483.             SHIFTNUM(token, s);
  1484.              if (1 != sscanf(token, "%d", &(pFar[nPolations])))
  1485.             {
  1486.                 FileFormatError("ReadDD2File", "Error in brainform");
  1487.                 break;
  1488.             }
  1489.             /*Calculate multiplying factor*/
  1490.             {
  1491.                 int n, f, d;
  1492.                 float d1, d2;
  1493.                 n = pNear[nPolations];
  1494.                 f = pFar[nPolations];
  1495.                 d = pDerived[nPolations];
  1496.  
  1497.                 d1 = sqrt(SQUARE(nodeBuf[f][0] - nodeBuf[n][0]) +
  1498.                       SQUARE(nodeBuf[f][1] - nodeBuf[n][1]) +
  1499.                       SQUARE(nodeBuf[f][2] - nodeBuf[n][2]));
  1500.                 d2 = sqrt(SQUARE(nodeBuf[d][0] - nodeBuf[n][0]) +
  1501.                       SQUARE(nodeBuf[d][1] - nodeBuf[n][1]) +
  1502.                       SQUARE(nodeBuf[d][2] - nodeBuf[n][2]));
  1503.                 if (pTypeChar == 'e' || pTypeChar == 'E')
  1504.                 {
  1505.                 pFac[nPolations] = - d2 / d1;
  1506.                 }
  1507.                 else
  1508.                 {
  1509.                 pFac[nPolations] = d2 / d1;
  1510.                 }
  1511.             }
  1512.             ++nPolations;
  1513.             break;
  1514.             default:
  1515.             FileFormatError("ReadDD2File", "Error in brainform");
  1516.         }
  1517.         }
  1518.         else
  1519.         {
  1520.         FileFormatError("ReadDD2File", "Error in brainform");
  1521.         }
  1522.     }
  1523.     fclose(inFile);
  1524.  
  1525.     /*Everything's been read.*/
  1526.  
  1527.     /*Make the vector dataset containing the nodes*/
  1528.     tempDims[0] = numNodes;
  1529.     tempDims[1] = numEdges;
  1530.     tempDims[2] = numCells;
  1531.     nodeData = NewDataset("brainform", 1, tempDims, 3);
  1532.     SetCurField(FIELD1, nodeData);
  1533.     bounds[0] = bounds[2] = bounds[4] = PLUSINF;
  1534.     bounds[1] = bounds[3] = bounds[5] = MINUSINF;
  1535.     for (k = 0; k < numNodes; ++k)
  1536.     {
  1537.         if (nodeBuf[k][0] < bounds[0]) bounds[0] = nodeBuf[k][0];
  1538.         if (nodeBuf[k][0] > bounds[1]) bounds[1] = nodeBuf[k][0];
  1539.         PutFieldComponent(FIELD1, 0, &k, nodeBuf[k][0]);
  1540.         if (nodeBuf[k][0] < bounds[2]) bounds[2] = nodeBuf[k][0];
  1541.         if (nodeBuf[k][0] > bounds[3]) bounds[3] = nodeBuf[k][0];
  1542.         PutFieldComponent(FIELD1, 1, &k, nodeBuf[k][1]);
  1543.         if (nodeBuf[k][0] < bounds[4]) bounds[4] = nodeBuf[k][0];
  1544.         if (nodeBuf[k][0] > bounds[5]) bounds[5] = nodeBuf[k][0];
  1545.         PutFieldComponent(FIELD1, 2, &k, nodeBuf[k][2]);
  1546.     }
  1547.  
  1548.     brainForm = NewUnstructuredDataForm("brainform", 2, tempDims, bounds, nodeData);
  1549.  
  1550.     edgeArray = NewRealArray(2, numEdges, 2L);
  1551.     if (!edgeArray)
  1552.     {
  1553.         Free(nodeBuf);
  1554.         Free(edgeBuf);
  1555.         return NULLOBJ;
  1556.     }
  1557.     CArray2Array(edgeArray, edgeBuf);
  1558.     SetVar(brainForm, EDGES, edgeArray);
  1559.     SetVar(brainForm, CELLS, cellList);
  1560.     Free(nodeBuf);
  1561.     Free(edgeBuf);
  1562.     }
  1563.  
  1564.     /*Get ready to read*/
  1565.     inFile = fopen(name, "r");
  1566.     if (!inFile)
  1567.     {
  1568.     Error("ReadDD2File", OPENFILEERROR, name);
  1569.     return NULLOBJ;
  1570.     }
  1571.     timeSteps = NewList();
  1572.     timeData = NewList();
  1573.  
  1574.     data = (real *) Alloc(sizeof(real) * numNodes);
  1575.  
  1576.     for (sample = 0; sample < DD2SAMPLES; ++sample)
  1577.     {
  1578.     ObjPtr sampleArray;
  1579.     if (21 != fscanf(inFile, " %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g",
  1580.         &data[0],
  1581.         &dummy,
  1582.         &data[1],
  1583.         &data[2],
  1584.         &data[3],
  1585.         &data[4],
  1586.         &data[5],
  1587.         &data[6],
  1588.         &data[7],
  1589.         &data[8],
  1590.         &data[9],
  1591.         &data[10],
  1592.         &data[11],
  1593.         &data[12],
  1594.         &data[13],
  1595.         &data[14],
  1596.         &data[15],
  1597.         &data[16],
  1598.         &data[17],
  1599.         &dummy,
  1600.         &data[18]
  1601.         ))
  1602.     {
  1603.         
  1604.         FileFormatError("ReadDD2File", "Not enough data");
  1605.         fclose(inFile);
  1606.         return NULLOBJ;
  1607.     }
  1608.  
  1609.     /*Fill in the polated data*/
  1610.         for (k = 0; k < nPolations; ++k)
  1611.     {
  1612.         data[pDerived[k]] = data[pNear[k]] + 
  1613.         (data[pFar[k]] - data[pNear[k]]) * pFac[k];
  1614.     }
  1615.  
  1616.     sampleArray = NewRealArray(1, (long) numNodes);
  1617.     CArray2Array(sampleArray, data);
  1618.     PostfixList(timeData, sampleArray);
  1619.     PostfixList(timeSteps, NewReal(DD2SECS * ((real) sample) / ((real) DD2SAMPLES)));
  1620.     }
  1621.  
  1622.     Free(data);
  1623.     fclose(inFile);
  1624.  
  1625.     retVal = NewObject(data3DUnstructSurface, 0);
  1626.     SetVar(retVal, DATA, NewTimedObject(timeSteps, timeData));
  1627.     SetVar(retVal, DATAFORM, brainForm);
  1628.     SetVar(retVal, NAME, MakeDatasetName(name));
  1629.     minMax[0] = -60.0;
  1630.     minMax[1] = 60.0;
  1631.     minMaxArray = NewRealArray(1, 2L);
  1632.     CArray2Array(minMaxArray, minMax);
  1633.     SetVar(retVal, MINMAX, minMaxArray);
  1634.  
  1635.     RegisterDataset(retVal);
  1636.     return NULLOBJ;
  1637. }
  1638.  
  1639. #define MAX_HDF_RANK 100    /*Maximum rank of HDF array*/
  1640.  
  1641. /*Values for out of bounds data*/
  1642. #define OB_MISSING    0    /*Treat as missing*/
  1643. #define OB_CLIP        1    /*Clip to bounds*/
  1644. #define OB_USE        2    /*Just use as is*/
  1645.  
  1646. #ifdef HDFDEF
  1647. ObjPtr ReadHDFFile(reader, fileName)
  1648. ObjPtr reader;
  1649. char *fileName;
  1650. /*Reads an HDF scientific data set (SDS) file.*/
  1651. {
  1652.     int nDataSets;        /*Number of data sets*/
  1653.     int whichSet;        /*Index into current data set*/
  1654.     ObjPtr var;            /*Random variable*/
  1655.     int outOfBoundsAction;    /*Action on out of bounds, based on
  1656.                   out of bounds radio button*/
  1657.  
  1658.     /*Step 1: Look for scientific data sets*/
  1659.  
  1660.     /*Find out the number of scientific datasets in the file*/
  1661. #ifdef HDF33
  1662.     nDataSets = DFSDndatasets(fileName);
  1663. #else
  1664.     nDataSets = DFSDnumber(fileName);
  1665. #endif
  1666.     if (nDataSets == -1)
  1667.     {
  1668.     char errMes[255];
  1669.     sprintf(errMes, "Cannot read HDF file %s.  The file is either missing or empty.\n", fileName);
  1670.         FileFormatError("ReadHDFFile", errMes);
  1671.         return NULLOBJ;
  1672.     }
  1673.  
  1674.     /*Determine action for out-of-bounds*/
  1675.     if ((var = GetIntVar("ReadHDFFile", reader, OUTOFBOUNDS)) == NULLOBJ)
  1676.     {
  1677.         outOfBoundsAction = OB_MISSING;
  1678.     }
  1679.     else
  1680.     {
  1681.         outOfBoundsAction = GetInt(var);
  1682.     }
  1683.  
  1684.     /*Go through the datasets, reading them in*/
  1685.     for (whichSet = 0; whichSet < nDataSets; ++whichSet)
  1686.     {
  1687.     /*Dataset characteristics from file*/
  1688.         int initRank;            /*Rank of the dataset*/
  1689.         long initDimSizes[MAX_HDF_RANK];/*Size of each dimension*/
  1690.     int adjustedRank;        /*Adjusted rank*/
  1691.     long *adjustedDimSizes;        /*Adjusted dim sizes*/
  1692.     int initDimPermutations[MAX_HDF_RANK];
  1693.                     /*Permutations of dimensions, i.e.,
  1694.                       for each dimension, which spatial
  1695.                       dim it corresponds to*/
  1696.     int *adjustedDimPermutations;    /*Adjusted for vector*/
  1697.     Bool dimUsed[MAX_HDF_RANK];    /*Flag to see if dim used*/
  1698.     real **initScales = 0;        /*Array for initial scales*/
  1699.     real **adjustedScales;        /*Scales adjusted for vector*/
  1700.     real **permutedScales = 0;    /*Permuted scales*/
  1701.     int nSpatialDimensions;        /*# of spatial dimensions used*/
  1702.     int *hdfToTopological = 0;    /*HDF dimension to topological dimension*/
  1703.     long *permutedDimSizes = 0;
  1704.         float min = PLUSINF;        /*Current minimum and maximum*/
  1705.     float max = MINUSINF;
  1706.     char dimsLabel[256];        /*Label of a dimension, used to determine which one*/
  1707.     char dimsUnit[256];        /*Units of a dimension, not used*/
  1708.     char dimsFormat[256];        /*Format of a dimension, not used*/
  1709.     char datasetName[256];        /*Name of a dataset*/
  1710.     char dataUnit[256];
  1711.     char dataFormat[256];
  1712.     char dataCoord[256];
  1713.     real cTable[256];        /*Compression table*/
  1714.     char *blanklessName;        /*Dataset name w/o leading blanks*/
  1715.     int k;                /*Random counter*/
  1716.     int vectorDim;            /*Dimension of vector*/
  1717.     int nComponents;        /*# of components*/
  1718.     ObjPtr xName = NULLOBJ;
  1719.     ObjPtr yName = NULLOBJ;
  1720.     ObjPtr zName = NULLOBJ;
  1721.     Bool isLeftHanded = false;    /*True iff dataset is likely to be left handed*/
  1722.  
  1723.     /*Variables for the dataset*/
  1724.         ObjPtr curField;        /*Field being assembled*/
  1725.     ObjPtr dataForm;        /*Data form*/
  1726.  
  1727.  
  1728.     int whichDim;            /*Which dimension working on*/
  1729.         int i;                /*Random counter*/
  1730.         long arraySize;            /*Total size of the array*/
  1731.         real intMissing = missingData;    /*Internal missing data*/
  1732.     Bool minMaxSet = false;        /*True iff min and max have been set*/
  1733.     Bool readVector = false;    /*True iff reading vector*/
  1734.     Bool wrapPolar = false;        /*True iff wrapping polar*/
  1735.     Bool compressData = true;    /*True iff compress data*/
  1736.     Bool botherWithAxes = true;    /*True iff compress data*/
  1737.     char dummy[256];        /*Dummy value for ignored strings*/
  1738.     float *tempData;
  1739.     long dataIndex;
  1740.     unsigned char cd;
  1741.     long *index, *permutedIndex;
  1742.     long componentSize;        /*Size of each component*/
  1743.  
  1744.         /*Start off with null field*/
  1745.         curField = 0;
  1746.  
  1747.     /*Assume it will be x, y, z*/
  1748.     xName = NewString("X");
  1749.     yName = NewString("Y");
  1750.     zName = NewString("Z");
  1751.  
  1752.         /*Get dimensions of dataset*/
  1753.         if (-1 == DFSDgetdims(fileName, &initRank, initDimSizes, (int) MAX_HDF_RANK)) 
  1754.         {
  1755.             FileFormatError("ReadHDFFile", "Unable to get dimensions.");
  1756.             return NULLOBJ;
  1757.         }
  1758.  
  1759.         /*See if there's a min and max defined in the dataset*/
  1760.         if (0 == DFSDgetrange(&max, &min))
  1761.         {
  1762.         if (min > max)
  1763.         {
  1764.         real temp;
  1765.         temp = max;
  1766.         max = min;
  1767.         min = temp;
  1768.         }
  1769.         minMaxSet = true;
  1770.         }
  1771.         else
  1772.         {
  1773.             min = MINUSINF; 
  1774.             max = PLUSINF;
  1775.         minMaxSet = false;
  1776.         }
  1777.  
  1778.     /*Temporary holding place for scales*/
  1779.     if (!(initScales = Alloc(sizeof(real *) * initRank)))
  1780.     {
  1781.         OMErr();
  1782.         return NULLOBJ;
  1783.     }
  1784.     for (whichDim = 0; whichDim < initRank; ++whichDim)
  1785.     {
  1786.         initScales[whichDim] = 0;
  1787.     }
  1788.         
  1789.     /*See if there's any possibility of reading vector data*/
  1790.     readVector = GetPredicate(reader, READVECTOR);
  1791.  
  1792.     /*See if there's any possibility of wrapping polar*/
  1793.     wrapPolar = GetPredicate(reader, WRAPPOLAR);
  1794.  
  1795.     /*See if we should bother with axes*/
  1796.     botherWithAxes = GetPredicate(reader, BOTHERWITHAXES);
  1797.  
  1798.     /*See if we want to compress data*/
  1799.     compressData = GetPredicate(reader, COMPRESSDATA);
  1800.  
  1801.     /*See if it's a scalar or vector dataset*/
  1802.     if (readVector && (initDimSizes[0] == 2 || initDimSizes[0] == 3))
  1803.     {
  1804.         /*It's vector, with the vector dimension at 0*/
  1805.         vectorDim = 0;
  1806.         nComponents = initDimSizes[0];
  1807.         adjustedRank = initRank - 1;
  1808.         adjustedDimSizes = &(initDimSizes[1]);
  1809.         adjustedScales = &(initScales[1]);
  1810.         adjustedDimPermutations = &(initDimPermutations[1]);
  1811.     }
  1812.     else if (readVector && (initDimSizes[initRank - 1] == 2 || initDimSizes[initRank - 1] == 3))
  1813.     {
  1814.         /*It's vector, with the vector dimension at initRank - 1*/
  1815.         vectorDim = initRank - 1;
  1816.         nComponents = initDimSizes[initRank - 1];
  1817.         adjustedRank = initRank - 1;
  1818.         adjustedDimSizes = initDimSizes;
  1819.         adjustedScales = initScales;
  1820.         adjustedDimPermutations = initDimPermutations;
  1821.     }
  1822.     else
  1823.     {
  1824.         /*It's scalar*/
  1825.         vectorDim = -1;
  1826.         adjustedRank = initRank;
  1827.         adjustedDimSizes = initDimSizes;
  1828.         adjustedScales = initScales;
  1829.         adjustedDimPermutations = initDimPermutations;
  1830.     }
  1831.  
  1832.     /*Get the name of the dataset*/
  1833.     datasetName[0] = '\0';
  1834.     if ((-1 == DFSDgetdatastrs(datasetName, dataUnit, dataFormat, dataCoord))
  1835.      || (datasetName[0] == '\0'))
  1836.     {
  1837.         strcpy(datasetName, fileName);
  1838.     }
  1839.     else
  1840.     {
  1841.         /*See about the coordinate system*/
  1842.         if ((0 == strcmp2(dataCoord, "polar")) || 
  1843.         (0 == strcmp2(dataCoord, "spherical")))
  1844.         {
  1845.         /*It's polar coordinates*/
  1846.         }
  1847.         else
  1848.         {
  1849.         /*It's not polar coordinates*/
  1850.         wrapPolar = false;
  1851.         }
  1852.     }
  1853.  
  1854.     /*Get the dimension information*/
  1855.     for (whichDim = 0; whichDim < initRank; ++whichDim)
  1856.     {
  1857.         float *tempScale;
  1858.     
  1859.         /*Get the strings for this dimension.*/
  1860.         initDimPermutations[whichDim] = -1;
  1861.         switch (whichDim)
  1862.         {
  1863.         case 0:
  1864.             strcpy(dimsLabel, "X");
  1865.             break;
  1866.         case 1:
  1867.             strcpy(dimsLabel, "Y");
  1868.             break;
  1869.         case 2:
  1870.             strcpy(dimsLabel, "Z");
  1871.             break;
  1872.         default:
  1873.             strcpy(dimsLabel, "");
  1874.             break;
  1875.         }
  1876.     
  1877.         if (botherWithAxes)
  1878.         {
  1879.         if (DFSDgetdimstrs(whichDim + 1, dimsLabel, dimsUnit, dimsFormat) != -1)
  1880.             {
  1881.         /*See if dimsLabel corresponds to a dimension*/
  1882.         initDimPermutations[whichDim] = FindAxisDimension(dimsLabel);
  1883.         if (initDimPermutations[whichDim] < 0)
  1884.         {
  1885.             /*Not found*/
  1886.             sprintf(tempStr, "Warning: Invalid axis", dimsLabel);
  1887.             FileFormatError("ReadHDFFile", tempStr);
  1888.         }
  1889.         else
  1890.         {
  1891.             switch(initDimPermutations[whichDim])
  1892.             {
  1893.             case 0:
  1894.                 xName = NewString(dimsLabel);
  1895.                 break;
  1896.             case 1:
  1897.                 yName = NewString(dimsLabel);
  1898.                 break;
  1899.             case 2:
  1900.                 zName = NewString(dimsLabel);
  1901.                 break;
  1902.             default:
  1903.                 break;
  1904.             }
  1905.         }
  1906.             }
  1907.         }
  1908.  
  1909.         /*Set up a place for the scales*/
  1910.             initScales[whichDim] = (real *) Alloc(initDimSizes[whichDim] * sizeof(real));
  1911.         if (!initScales[whichDim]) {OMErr(); return NULLOBJ;}
  1912.  
  1913.         /*And a temporary scale*/
  1914.         tempScale = (float *) Alloc(initDimSizes[whichDim] * sizeof(float));
  1915.         if (!tempScale) {OMErr(); return NULLOBJ;}
  1916.  
  1917.         /*Get the scale from the file*/
  1918.         if (DFSDgetdimscale(whichDim + 1, initDimSizes[whichDim], tempScale) != -1)
  1919.         {
  1920.         double circ = 0.0;
  1921.  
  1922.         /*Just copy the read scale*/
  1923.         for (i = 0; i < initDimSizes[whichDim]; ++i)
  1924.         {
  1925.             initScales[whichDim][i] = tempScale[i];
  1926.         }
  1927.  
  1928.         /*See if we need to wrap*/
  1929.         if (wrapPolar)
  1930.         {
  1931.         if ((strcmp(dimsUnit, "degrees") == 0)) circ = 360.0;
  1932.         else if ((strcmp(dimsUnit, "radians") == 0)) circ = 2.0 * M_PI;
  1933.         else if ((strcmp(dimsUnit, "gradians") == 0)) circ = 400.0;
  1934.         if (circ > 0.0)
  1935.         {
  1936.             /*Let's wrap*/
  1937.             if (initScales[whichDim][1] < initScales[whichDim][0])
  1938.             {
  1939.             /*Down*/
  1940.             for (i = 2; i < initDimSizes[whichDim]; ++i)
  1941.             {
  1942.                 while (initScales[whichDim][i] > initScales[whichDim][i - 1])
  1943.                 {
  1944.                 initScales[whichDim][i] -= circ;
  1945.                 }
  1946.             }
  1947.             }
  1948.             else
  1949.             {
  1950.             /*Up*/
  1951.             for (i = 2; i < initDimSizes[whichDim]; ++i)
  1952.             {
  1953.                 while (initScales[whichDim][i] < initScales[whichDim][i - 1])
  1954.                 {
  1955.                 initScales[whichDim][i] += circ;
  1956.                 }
  1957.             }
  1958.             }
  1959.         }
  1960.         }
  1961.         }
  1962.         else
  1963.         {
  1964.         /*Guess the scale*/
  1965.         
  1966.         if (whichDim != vectorDim)
  1967.         {
  1968.             sprintf(tempStr, "Guessing scale %d from %d to %d", whichDim, 0, initDimSizes[whichDim] - 1);
  1969.             FileFormatError("ReadHDFFile", tempStr);
  1970.         }
  1971.  
  1972.         /*Fill in the scale based on the guess*/
  1973.         for (i = 0; i < initDimSizes[whichDim]; ++i)
  1974.         {
  1975.             initScales[whichDim][i] = (real) i;
  1976.                 }
  1977.             }
  1978.         Free(tempScale);
  1979.     }
  1980.  
  1981.     /*Fill in unpermuted axes*/
  1982.     for (k = 0; k < MAX_HDF_RANK; ++k)
  1983.     {
  1984.         dimUsed[k] = false;
  1985.     }
  1986.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  1987.     {
  1988.         if (adjustedDimPermutations[whichDim] >= 0)
  1989.         {
  1990.         if (dimUsed[adjustedDimPermutations[whichDim]])
  1991.         {
  1992.             sprintf(tempStr, "Dimension %d is used more than once", whichDim);
  1993.             FileFormatError("ReadHDFFile", tempStr);
  1994.             adjustedDimPermutations[whichDim] = -1;
  1995.         }
  1996.         else
  1997.         {
  1998.             dimUsed[adjustedDimPermutations[whichDim]] = true;
  1999.         }
  2000.         }
  2001.     }
  2002.  
  2003.     k = 0;
  2004.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2005.     {
  2006.         if (adjustedDimPermutations[whichDim] < 0)
  2007.         {
  2008.         while (dimUsed[k]) ++k;
  2009.         adjustedDimPermutations[whichDim] = k;
  2010.         dimUsed[k] = true;
  2011.         ++k;
  2012.         }
  2013.     }
  2014.  
  2015.     /*Find # of spatial dimensions used*/
  2016.     nSpatialDimensions = 0;
  2017.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2018.     {
  2019.         nSpatialDimensions = MAX(nSpatialDimensions, adjustedDimPermutations[whichDim] + 1);
  2020.     }
  2021.  
  2022.     /*Make HDF to topological dimension mapping*/
  2023.     hdfToTopological = (int *) Alloc(sizeof(int) * adjustedRank);
  2024.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2025.     {
  2026.         hdfToTopological[whichDim] = 0;
  2027.         for (k = 0; k < adjustedDimPermutations[whichDim]; ++k)
  2028.         {
  2029.         if (dimUsed[k])
  2030.         {
  2031.             ++hdfToTopological[whichDim];
  2032.         }
  2033.         }
  2034.     }
  2035.  
  2036.     /*Make permuted dim sizes*/
  2037.     permutedDimSizes = (long *) Alloc(sizeof(long) * adjustedRank);
  2038.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2039.     {
  2040.         permutedDimSizes[hdfToTopological[whichDim]] = adjustedDimSizes[whichDim];
  2041.     }
  2042.  
  2043.     /*Make permuted scales*/
  2044.     permutedScales = (real **) Alloc(sizeof(real *) * adjustedRank);
  2045.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2046.     {
  2047.         permutedScales[hdfToTopological[whichDim]] = adjustedScales[whichDim];
  2048.     }
  2049.  
  2050.     /*See if it's left-handed or not*/
  2051.     isLeftHanded = false;
  2052.     for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2053.     {
  2054.         if (adjustedScales[whichDim][1] < adjustedScales[whichDim][0])
  2055.         {
  2056.         isLeftHanded = isLeftHanded ? false : true;
  2057.         }
  2058.     }
  2059.  
  2060.     /*Remove leading blanks on label*/
  2061.     blanklessName = datasetName;
  2062.     while (*blanklessName && *blanklessName == ' ') ++blanklessName;
  2063.     
  2064.     /*Make the new data form*/
  2065.     dataForm = NewSeparableDataForm(blanklessName, adjustedRank, permutedDimSizes, permutedScales);
  2066.  
  2067.     /*Calculate the size of the array we'll need for the dataset*/
  2068.     arraySize = 1;
  2069.     for (i = 0; i < initRank; ++i)
  2070.     {
  2071.         arraySize *= initDimSizes[i];
  2072.     }
  2073.  
  2074.     /*Make the temp data*/
  2075.     tempData = (float *) Alloc(arraySize * sizeof(float));
  2076.  
  2077.     /*Calculate the size of one component*/
  2078.     if (vectorDim < 0)
  2079.     {
  2080.         componentSize = arraySize;
  2081.     }
  2082.     else
  2083.     {
  2084.         componentSize = arraySize / nComponents;
  2085.     }
  2086.  
  2087.     /*Read in the data*/
  2088.     if (-1 == DFSDgetdata(fileName, initRank, initDimSizes, tempData))
  2089.     {
  2090.         FileFormatError("ReadHDFFile", "Can't read field data.");
  2091.         return NULLOBJ;
  2092.     }
  2093.  
  2094.     if (minMaxSet && (outOfBoundsAction != OB_USE))
  2095.     {
  2096.         /*Search for out of bounds data*/
  2097.         for (dataIndex = 0; dataIndex < arraySize; ++dataIndex)
  2098.         {
  2099.         if (tempData[dataIndex] < min)
  2100.         {
  2101.             tempData[dataIndex] = (outOfBoundsAction == OB_CLIP) ? min : missingData;
  2102.         }
  2103.         else
  2104.         {
  2105.             if (tempData[dataIndex] > max)
  2106.             {
  2107.             tempData[dataIndex] = (outOfBoundsAction == OB_CLIP) ? max : missingData;
  2108.             }
  2109.         }
  2110.         }
  2111.     }
  2112.  
  2113.     if (!minMaxSet)
  2114.     {
  2115.         /*Go through and look for min and max*/
  2116.         for (dataIndex = 0; dataIndex < arraySize; ++dataIndex)
  2117.         {
  2118.         if (tempData[dataIndex] != missingData)
  2119.         {
  2120.             if (minMaxSet)
  2121.             {
  2122.             min = MIN(min, tempData[dataIndex]);
  2123.             max = MAX(max, tempData[dataIndex]);
  2124.             }
  2125.             else
  2126.             {
  2127.             min = max = tempData[dataIndex];
  2128.             minMaxSet = true;
  2129.             }
  2130.         }
  2131.         }
  2132.     }
  2133.  
  2134.     /*Make compression table*/
  2135.     if (compressData)
  2136.     {
  2137.         cTable[0] = missingData;
  2138.         for (k = 1; k < 256; ++k)
  2139.         {
  2140.         cTable[k] = min + (max - min) * (k - 1) / 254.0;
  2141.         }
  2142.     }
  2143.  
  2144.     /*Make the new dataset*/
  2145.     if (compressData)
  2146.     {
  2147.         curField = NewCompressedDataset(blanklessName, adjustedRank, permutedDimSizes, vectorDim > 0 ? nComponents : 0, cTable);
  2148.     }
  2149.     else
  2150.     {
  2151.         curField = NewDataset(blanklessName, adjustedRank, permutedDimSizes, vectorDim > 0 ? nComponents : 0);
  2152.     }
  2153.  
  2154.     if (isLeftHanded)
  2155.     {
  2156.         SetVar(curField, ISLEFTHANDED, ObjTrue);
  2157.     }
  2158.  
  2159.     /*Put in axis names*/
  2160.     if (xName)
  2161.     {
  2162.         SetVar(curField, XNAME, xName);
  2163.     }
  2164.     if (yName)
  2165.     {
  2166.         SetVar(curField, YNAME, yName);
  2167.     }
  2168.     if (zName)
  2169.     {
  2170.         SetVar(curField, ZNAME, zName);
  2171.     }
  2172.  
  2173.     /*Link the data form with the field*/
  2174.     SetVar(curField, DATAFORM, dataForm);
  2175.     /*Set the current field for reading data in*/
  2176.     SetCurField(FIELD1, curField);
  2177.  
  2178.     /*Set up the indices*/
  2179.     index = (long *) Alloc(sizeof(long) * adjustedRank);
  2180.     permutedIndex = (long *) Alloc(sizeof(long) * adjustedRank);
  2181.  
  2182.     if (vectorDim < 0)
  2183.     {
  2184.         /*Scalar dataset*/
  2185.  
  2186.         /*Zero the indices*/
  2187.         for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2188.         {
  2189.         index[whichDim] = 0;
  2190.         }
  2191.  
  2192.         for (dataIndex = 0; dataIndex < componentSize; ++dataIndex)
  2193.         {
  2194.         /*Permute the index*/
  2195.         for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2196.         {
  2197.             permutedIndex[hdfToTopological[whichDim]] = index[whichDim];
  2198.         }
  2199.  
  2200.         if (compressData)
  2201.         {
  2202.             if (tempData[dataIndex] == missingData)
  2203.             {
  2204.             cd = 0;
  2205.             }
  2206.             else
  2207.             {
  2208.             cd = 1.5  + (tempData[dataIndex] - min) / (max - min) * 254.0;
  2209.             if (cd < 1) cd = 1;
  2210.             if (cd > 255) cd = 255;
  2211.             }
  2212.             PutCompressedFieldComponent(FIELD1, 0, permutedIndex, cd);
  2213.         }
  2214.         else
  2215.         {
  2216.             PutFieldComponent(FIELD1, 0, permutedIndex, tempData[dataIndex]);
  2217.         }
  2218.  
  2219.         /*Advance to next index*/
  2220.         for (whichDim = adjustedRank - 1; whichDim >= 0; --whichDim)
  2221.         {
  2222.             if ((++index[whichDim]) >= adjustedDimSizes[whichDim])
  2223.             {
  2224.             index[whichDim] = 0;
  2225.             }
  2226.             else
  2227.             {
  2228.             break;
  2229.             }
  2230.         }
  2231.         }
  2232.     }
  2233.     else if (vectorDim == 0)
  2234.     {
  2235.         float *dataChunk;
  2236.         /*Vector index on 0*/
  2237.  
  2238.         for (k = 0; k < nComponents; ++k)
  2239.         {
  2240.         /*Zero the indices*/
  2241.         for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2242.         {
  2243.             index[whichDim] = 0;
  2244.         }
  2245.  
  2246.         dataChunk = tempData + k * componentSize;
  2247.  
  2248.         for (dataIndex = 0; dataIndex < componentSize; ++dataIndex)
  2249.         {
  2250.             /*Permute the index*/
  2251.             for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2252.             {
  2253.             permutedIndex[hdfToTopological[whichDim]] = index[whichDim];
  2254.             }
  2255.             if (compressData)
  2256.             {
  2257.             if (dataChunk[dataIndex] == missingData)
  2258.             {
  2259.                 cd = 0;
  2260.             }
  2261.             else
  2262.             {
  2263.                 cd = 1.5  + (dataChunk[dataIndex] - min) / (max - min) * 254.0;
  2264.                 if (cd < 1) cd = 1;
  2265.                 if (cd > 255) cd = 255;
  2266.             }
  2267.             PutCompressedFieldComponent(FIELD1, k, permutedIndex, cd);
  2268.             }
  2269.             else
  2270.             {
  2271.             PutFieldComponent(FIELD1, k, permutedIndex, dataChunk[dataIndex]);
  2272.             }
  2273.  
  2274.             /*Advance to next index*/
  2275.             for (whichDim = adjustedRank - 1; whichDim >= 0; --whichDim)
  2276.             {
  2277.                 if ((++index[whichDim]) >= adjustedDimSizes[whichDim])
  2278.                 {
  2279.                 index[whichDim] = 0;
  2280.             }
  2281.             else
  2282.             {
  2283.                 break;
  2284.             }
  2285.             }
  2286.         }
  2287.         }
  2288.     }
  2289.     else
  2290.     {
  2291.         /*Vector index on last dim*/
  2292.  
  2293.         /*Zero the indices*/
  2294.         for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2295.         {
  2296.         index[whichDim] = 0;
  2297.         }
  2298.  
  2299.         for (dataIndex = 0; dataIndex < componentSize * nComponents; dataIndex += nComponents)
  2300.         {
  2301.         /*Permute the index*/
  2302.         for (whichDim = 0; whichDim < adjustedRank; ++whichDim)
  2303.         {
  2304.             permutedIndex[hdfToTopological[whichDim]] = index[whichDim];
  2305.         }
  2306.  
  2307.         for (k = 0; k < nComponents; ++k)
  2308.         {
  2309.             if (compressData)
  2310.             {
  2311.             if (tempData[dataIndex + k] == missingData)
  2312.             {
  2313.                 cd = 0;
  2314.             }
  2315.             else
  2316.             {
  2317.                 cd = 1.5  + (tempData[dataIndex + k] - min) / (max - min) * 254.0;
  2318.                 if (cd < 1) cd = 1;
  2319.                 if (cd > 255) cd = 255;
  2320.             }
  2321.             PutCompressedFieldComponent(FIELD1, k, permutedIndex, cd);
  2322.             }
  2323.             else
  2324.             {
  2325.             PutFieldComponent(FIELD1, k, permutedIndex, tempData[dataIndex + k]);
  2326.             }
  2327.         }
  2328.  
  2329.         /*Advance to next index*/
  2330.         for (whichDim = adjustedRank - 1; whichDim >= 0; --whichDim)
  2331.         {
  2332.             if ((++index[whichDim]) >= adjustedDimSizes[whichDim])
  2333.             {
  2334.             index[whichDim] = 0;
  2335.             }
  2336.             else
  2337.             {
  2338.             break;
  2339.             }
  2340.         }
  2341.         }
  2342.     }
  2343.  
  2344.     SAFEFREE(index);
  2345.     SAFEFREE(permutedIndex);
  2346.  
  2347.     /*Set the min and max*/
  2348.     if (minMaxSet)
  2349.     {
  2350.         if (vectorDim < 0)
  2351.         {
  2352.         /*Scalar field, just do as normal*/
  2353.         real minMax[2];
  2354.         ObjPtr minMaxArray;
  2355.         minMax[0] = min;
  2356.         minMax[1] = max;
  2357.         minMaxArray = NewRealArray(1, 2L);
  2358.         CArray2Array(minMaxArray, minMax);
  2359.         SetVar(curField, MINMAX, minMaxArray);
  2360.         }
  2361.         else
  2362.         {
  2363.         /*Vector field, adjust it a bit*/
  2364.         real minMax[2];
  2365.         ObjPtr minMaxArray;
  2366.         minMax[0] = 0.0;
  2367.         minMax[1] = MAX(max, -min);
  2368.         minMaxArray = NewRealArray(1, 2L);
  2369.         CArray2Array(minMaxArray, minMax);
  2370.         SetVar(curField, MINMAX, minMaxArray);
  2371.         }
  2372.     }
  2373.  
  2374.     /*Free the temp data*/
  2375.     SAFEFREE(tempData);
  2376.     SAFEFREE(permutedDimSizes);
  2377.     SAFEFREE(hdfToTopological);
  2378.  
  2379.     /*Free scales*/
  2380.     for (i = 0; i < initRank; ++i)
  2381.     {
  2382.         if (initScales[i]) Free(initScales[i]);
  2383.     }
  2384.     SAFEFREE(initScales);
  2385.     SAFEFREE(permutedScales);
  2386.  
  2387.         /*Register the dataset*/
  2388.         if (curField)
  2389.         {
  2390.             RegisterDataset(curField);
  2391.         }
  2392.     }
  2393.  
  2394.     /*Make the file go back to the beginning*/
  2395.     DFSDrestart();
  2396.  
  2397.     return NULLOBJ;
  2398. } /* ReadHDFFile */
  2399. #endif
  2400.  
  2401. #ifdef PROTO
  2402. ObjPtr NewFileReader(char *name)
  2403. #else
  2404. ObjPtr NewFileReader(name)
  2405. char *name;
  2406. #endif
  2407. {
  2408.     ObjPtr fileReader;
  2409.     ThingListPtr runner;
  2410.     ObjPtr nameVar;
  2411.  
  2412.     fileReader = NewObject(fileReaderClass, 0);
  2413.     SetVar(fileReader, NAME, NewString(name));
  2414.  
  2415.     AddObjToDatabase(fileReader);
  2416.  
  2417.     return fileReader;
  2418. }
  2419.  
  2420. void DefineFormat(name, extension, reader, writer)
  2421. char *name;
  2422. char *extension;
  2423. ObjPtr (*reader)();
  2424. Bool (*writer)();
  2425. /*Defines a format with name, reader, and writer*/
  2426. {
  2427.     ObjPtr fileReader;
  2428.  
  2429.     fileReader = NewFileReader(name);
  2430.     SetVar(fileReader, EXTENSION, NewString(extension));
  2431.     SetMethod(fileReader, OLDREAD, reader);
  2432.     ApplySavedSettings(fileReader);
  2433. }
  2434.  
  2435. ObjPtr FindFormatReader(format)
  2436. char *format;
  2437. /*Finds the file reader named format*/
  2438. {
  2439.     ObjPtr keyList;
  2440.     ThingListPtr runner;
  2441.     ObjPtr fileReaders;
  2442.  
  2443.     /*Search database for datasets*/
  2444.     keyList = NewList();
  2445.     PostfixList(keyList, NewSymbol(CLASSID));
  2446.     PostfixList(keyList, NewInt(CLASS_FILEREADER));
  2447.     PostfixList(keyList, NewSymbol(NAME));
  2448.     PostfixList(keyList, NewString(format));
  2449.  
  2450.     fileReaders = SearchDatabase(keyList);
  2451.  
  2452.     if (fileReaders)
  2453.     {
  2454.     runner = LISTOF(fileReaders);
  2455.     if (runner)
  2456.     {
  2457.         if (runner -> next)
  2458.         {
  2459.         ReportError("FindFormatReader", "Duplicate file reader");
  2460.         }
  2461.         return runner -> thing;
  2462.     }
  2463.     }
  2464.     return NULLOBJ;
  2465. }
  2466.  
  2467. ObjPtr FindExtensionReader(ext)
  2468. char *ext;
  2469. /*Finds the file reader for extension ext*/
  2470. {
  2471.     ObjPtr keyList;
  2472.     ThingListPtr runner;
  2473.     ObjPtr fileReaders;
  2474.  
  2475.     /*Search database for datasets*/
  2476.     keyList = NewList();
  2477.     PostfixList(keyList, NewSymbol(CLASSID));
  2478.     PostfixList(keyList, NewInt(CLASS_FILEREADER));
  2479.     PostfixList(keyList, NewSymbol(EXTENSION));
  2480.     PostfixList(keyList, NewString(ext));
  2481.  
  2482.     fileReaders = SearchDatabase(keyList);
  2483.  
  2484.     if (fileReaders)
  2485.     {
  2486.     runner = LISTOF(fileReaders);
  2487.     if (runner)
  2488.     {
  2489.         if (runner -> next)
  2490.         {
  2491.         ReportError("FindExtensionReader", "Duplicate file reader");
  2492.         }
  2493.         return runner -> thing;
  2494.     }
  2495.     }
  2496.     return NULLOBJ;
  2497. }
  2498.  
  2499. ObjPtr ReadFormattedFile(reader, name)
  2500. char *name;
  2501. ObjPtr reader;
  2502. /*Reads file name with reader.*/
  2503. {
  2504.     FuncTyp method;
  2505.     ObjPtr retVal;
  2506.  
  2507.     if (!reader) return ObjFalse;
  2508.  
  2509.     timedDatasets = GetPredicate(reader, TIMEDDATASETS) ? true : false;
  2510.     method = GetMethodSurely("ReadFormattedFile", reader, READALL);
  2511.     if (!method)
  2512.     {
  2513.     return ObjFalse;
  2514.     }
  2515.  
  2516.     /*Read the file*/
  2517.     curFileName = name;
  2518.     retVal = (*method)(reader, name);
  2519.     curFileName = 0;
  2520.     return retVal;
  2521. }
  2522.  
  2523. void ReadFile(name, format)
  2524. char *name;
  2525. char *format;
  2526. /*Reads a file from the current directory with name and format format.
  2527.   If format points to a null string, looks for a format*/
  2528. {
  2529.     ObjPtr reader;
  2530.     ObjPtr allFileReaders;
  2531.  
  2532.     if (format[0])
  2533.     {
  2534.     /*There's a format specified*/
  2535.     reader = FindFormatReader(format);
  2536.     if (!reader)
  2537.     {
  2538.         WinInfoPtr errWindow;
  2539.         char err[200];
  2540.         sprintf(err, "There is no format named %s\n", format);
  2541.         errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, err, 0, 0, "OK");
  2542.         SetVar((ObjPtr) errWindow, HELPSTRING,
  2543.         NewString("You have specified on the SciAn command line a format \
  2544. that does not exist, or you left out the format string entirely.  This has \
  2545. prevented SciAn from reading the file.  You can read it now using the \
  2546. file browser, which you can show by choosing New File Browser from the File menu."));
  2547.         SetVar((ObjPtr) errWindow, INHIBITLOGGING, ObjTrue);
  2548.         return;
  2549.         }
  2550.     }
  2551.     else
  2552.     {
  2553.     char *s;
  2554.     /*Must find a format*/
  2555.  
  2556.     s = name;
  2557.     while (*s) ++s;
  2558.     while (s >= name && *s != '.') --s;
  2559.     if (*s == '.')
  2560.     {
  2561.         reader = FindExtensionReader(s + 1);
  2562.     }
  2563.     else
  2564.     {
  2565.         reader = NULLOBJ;
  2566.     }
  2567.     if (!reader)
  2568.     {
  2569.         WinInfoPtr errWindow;
  2570.         char err[200];
  2571.         sprintf(err, "There is no default format for file %s\n", name);
  2572.         errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, err, 0, 0, "yeah?");
  2573.         SetVar((ObjPtr) errWindow, HELPSTRING,
  2574.         NewString("You have specified on the SciAn command line a file \
  2575. whose format cannot be deduced from the name.  This has \
  2576. prevented SciAn from reading the file.  You can read it now using the \
  2577. file browser, which you can show by choosing New File Browser from the File menu."));
  2578.         SetVar((ObjPtr) errWindow, INHIBITLOGGING, ObjTrue);
  2579.         return;
  2580.         }
  2581.     }
  2582.     ReadFormattedFile(reader, name);
  2583. }
  2584.  
  2585. static ObjPtr HideFileReadersWindow(window)
  2586. ObjPtr window;
  2587. /*Hide a file readers window, just return OK*/
  2588. {
  2589.     return ObjTrue;
  2590. }
  2591.  
  2592. WinInfoPtr NewFileReadersWindow(void)
  2593. /*Create a new file readers window*/
  2594. {
  2595.     WinInfoPtr objWin;
  2596.     ThingListPtr runner;
  2597.     ObjPtr panel, contents, corral, button;
  2598.     int bw;
  2599.     int l, r, b, t;
  2600.     ObjPtr allFileReaders;
  2601.     ObjPtr keyList;
  2602.  
  2603.     /*Create the window*/
  2604.     objWin = NewObjWindow(NULLOBJ, "File Readers", WINUI, FRWINWIDTH, FRWINHEIGHT, SCRWIDTH, SCRHEIGHT);
  2605.  
  2606.     /*Set a null but successful HIDE routine*/
  2607.     SetMethod((ObjPtr) objWin, HIDE, HideFileReadersWindow);
  2608.  
  2609.     /*Add a help string*/
  2610.     SetVar((ObjPtr) objWin, HELPSTRING, 
  2611.     NewString("This window shows all the file readers in Scian."));
  2612.  
  2613.     /*Put in a panel*/
  2614.     panel = NewPanel(greyPanelClass, 0, FRWINWIDTH, 0, FRWINHEIGHT);
  2615.     SetVar(panel, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT +
  2616.                      STICKYBOTTOM + STICKYTOP));
  2617.  
  2618.     contents = GetVar((ObjPtr) objWin, CONTENTS);
  2619.     PrefixList(contents, panel);
  2620.     SetVar(panel, PARENT, (ObjPtr) objWin);
  2621.  
  2622.     l = 0; r = FRWINWIDTH; b = 0; t = FRWINHEIGHT;
  2623.  
  2624.     /*Put in buttons and an icon corral*/
  2625.     contents = GetListVar("NewDatasetsWindow", panel, CONTENTS);
  2626.     if (!contents)
  2627.     {
  2628.     return 0;
  2629.     }
  2630.     /*Make an icon corral*/
  2631.     corral = NewIconCorral(NULLOBJ, l + MINORBORDER, r - MINORBORDER, b + 2 * MINORBORDER + BUTTONHEIGHT, t - MINORBORDER, BARRIGHT + BARBOTTOM);
  2632.     SetVar(corral, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT +
  2633.                      STICKYBOTTOM + STICKYTOP));
  2634.     SetVar(corral, TOPDOWN, ObjTrue);
  2635.     SetVar(corral, NAME, NewString("File Readers Corral"));
  2636.     SetVar(corral, HELPSTRING,
  2637.     NewString("This corral contains icons for all the file readers in \
  2638. SciAn.  You can show the controls of any file readers by selecting \
  2639. the icons and pressing the Show Controls button at the bottom of the window."));
  2640.     PrefixList(contents, corral);
  2641.     SetVar(corral, PARENT, panel);
  2642.     SetVar((ObjPtr) objWin, CORRAL, corral);
  2643.  
  2644.     l += MINORBORDER;
  2645.     r -= MINORBORDER;
  2646.     b += MINORBORDER;
  2647.     t = b + BUTTONHEIGHT;
  2648.     bw = (r - l - MINORBORDER) / 2;
  2649.  
  2650.     /*Make a show info button*/
  2651.     button = NewFunctionButton(objWin,
  2652.         l, l + bw, 
  2653.         b, b + BUTTONHEIGHT, OF_SHOW_CONTROLS); 
  2654.     if (button)
  2655.     {
  2656.     SetVar(button, PARENT, panel);
  2657.     SetVar(button, STICKINESS, NewInt(STICKYBOTTOM + STICKYLEFT + FLOATINGRIGHT));
  2658.     PrefixList(contents, button);
  2659.     }
  2660.  
  2661.     /*Drop all the file readers into the window*/
  2662.     keyList = NewList();
  2663.     PostfixList(keyList, NewSymbol(CLASSID));
  2664.     PostfixList(keyList, NewInt(CLASS_FILEREADER));
  2665.  
  2666.     allFileReaders = SearchDatabase(keyList);
  2667.  
  2668.     runner = LISTOF(SortListByStringVar(allFileReaders, NAME, true));
  2669.  
  2670.     while(runner)
  2671.     {
  2672.     ObjPtr icon, name;
  2673.     FuncTyp method;
  2674.     
  2675.     icon = GetVar(runner -> thing, DEFAULTICON);
  2676.     if (!icon)
  2677.     {
  2678.         icon = NewIcon(0, 0, ICONFILEREADER, "?");
  2679.     }
  2680.     else
  2681.     {
  2682.         icon = NewObject(icon, 0L);
  2683.     }
  2684.     name = GetVar(runner -> thing, NAME);
  2685.     SetVar(icon, NAME, name);
  2686.  
  2687.     SetVar(icon, ICONLOC, NULLOBJ);
  2688.     SetVar(icon, REPOBJ, runner -> thing);
  2689.     SetVar(icon, CORRAL, corral);
  2690.     DropIconSeriesInCorral(corral, icon);
  2691.  
  2692.     runner = runner -> next;
  2693.     }
  2694.  
  2695.     return objWin;
  2696. }
  2697.  
  2698. WinInfoPtr FileReadersWindow()
  2699. /*Returns or creates a file readers window*/
  2700. {
  2701.     WinInfoPtr retVal;
  2702.  
  2703.     retVal = GetWinFromTitle("File Readers");
  2704.     if (!retVal)
  2705.     {
  2706.     retVal = NewFileReadersWindow();
  2707.     }
  2708.     return retVal;
  2709. }
  2710.  
  2711. static ObjPtr ReadOldFile(fileReader, name)
  2712. ObjPtr fileReader;
  2713. char *name;
  2714. /*Method to read a file using an old style file reader*/
  2715. {
  2716.     FuncTyp method;
  2717.     method = GetMethodSurely("ReadOldFile", fileReader, OLDREAD);
  2718.     if (!method)
  2719.     {
  2720.     return ObjFalse;
  2721.     }
  2722.     (*method)(name);
  2723.     return ObjTrue;
  2724. }
  2725.  
  2726. static ObjPtr ShowFileReaderControls(fileReader, windowName)
  2727. ObjPtr fileReader;
  2728. char *windowName;
  2729. /*Makes a new control window to control a file reader*/
  2730. {
  2731.     WinInfoPtr controlWindow;
  2732.     ObjPtr var;
  2733.     ObjPtr panel;
  2734.     ObjPtr contents;
  2735.     WinInfoPtr dialogExists;
  2736.  
  2737.     dialogExists = DialogExists((WinInfoPtr) fileReader, NewString("Controls"));
  2738.     if (!dialogExists)
  2739.     {
  2740.     ObjPtr textBox, checkBox;
  2741.     int contentsRight, contentsTop;
  2742.     int left, right, bottom, top, mid;
  2743.     int l, r, b, t;
  2744.     ObjPtr list;
  2745.     ThingListPtr runner;
  2746.     FuncTyp method;
  2747.     ObjPtr button;
  2748.  
  2749.     /*Make the panel*/
  2750.     panel = NewPanel(greyPanelClass, 0, 10, 0, 10);
  2751.     if (!panel)
  2752.     {
  2753.         return ObjFalse;
  2754.     }
  2755.     contents = GetVar(panel, CONTENTS);
  2756.     SetVar(contents, PARENT, panel);
  2757.  
  2758.     /*Give file reader chance to add controls*/
  2759.     method = GetMethod(fileReader, ADDCONTROLS);
  2760.     if (method)
  2761.     {
  2762.         (*method)(fileReader, contents);
  2763.     }
  2764.  
  2765.     /*Calculate the bounds*/
  2766.     contentsRight = contentsTop = 0;
  2767.     runner = LISTOF(contents);
  2768.     while (runner)
  2769.     {
  2770.         Get2DIntBounds(runner -> thing, &left, &right, &bottom, &top);
  2771.         contentsRight = MAX(contentsRight, right);
  2772.         contentsTop = MAX(contentsTop, top);
  2773.         runner = runner -> next;
  2774.     }
  2775.  
  2776.     bottom = contentsTop + MAJORBORDER;
  2777.     left = MAJORBORDER;
  2778.  
  2779.     /*Create the check box for time dependency*/
  2780.     top = bottom + CHECKBOXHEIGHT;
  2781.     right = left + FRTIMEWIDTH;
  2782.     checkBox = NewCheckBox(left, right, bottom, top,
  2783.         "Use \"field@time\" format for time samples",
  2784.         GetPredicate(fileReader, TIMEDDATASETS));
  2785.     SetVar(checkBox, PARENT, panel);
  2786.     PrefixList(contents, checkBox);
  2787.     bottom = top + MINORBORDER;
  2788.     if (!GetVar(fileReader, TIMEDDATASETS))
  2789.     {
  2790.         SetVar(fileReader, TIMEDDATASETS, ObjTrue);
  2791.     }
  2792.     AssocDirectControlWithVar(checkBox, fileReader, TIMEDDATASETS);
  2793.     SetVar(checkBox, HELPSTRING, 
  2794.         NewString("If this check box is checked, any dataset name of the \
  2795. form \"name@time\" will be interpreted as a sample of field name at time time.  \
  2796. The time string can be a single number, in which case it will be interpreted \
  2797. as seconds or timesteps, or it can be a string in the form hh:mm:ss, or clock \
  2798. format.  For example, a dataset named \"Z@12:04:00\" is a sample for the file \
  2799. Z taken at 12:04:00.  This feature provides an easy way to get time-dependent \
  2800. data from file formats that are only suited to static data.\n\
  2801. \n\
  2802. If this check box is not checked, dataset names will be used as they appear, \
  2803. even if they contain the \"@\" character.  Any inherent capability of the file \
  2804. reader to read time-dependent data will continue to work, of course."));
  2805.  
  2806.     /*Create the default file extension box*/
  2807.     top = bottom + EDITBOXHEIGHT;
  2808.     right = left + FREXTTITLEWIDTH;
  2809.     mid = (bottom + top) / 2;
  2810.     textBox = NewTextBox(left, right,
  2811.         mid - TEXTBOXHEIGHT / 2 + EDITBOXDOWN, 
  2812.         mid + TEXTBOXHEIGHT / 2 + EDITBOXDOWN,
  2813.         0, "Default Extension Text", "Default Extension:");
  2814.     SetVar(textBox, PARENT, panel);
  2815.     PrefixList(contents, textBox);
  2816.  
  2817.     /*Create the editable box*/
  2818.     left = right + MAJORBORDER;
  2819.     right = left + FREXTTEXTWIDTH;
  2820.     var = GetVar(fileReader, EXTENSION);
  2821.     if (!var)
  2822.     {
  2823.         var = NewString("");
  2824.         SetVar(fileReader, EXTENSION, var);
  2825.     }
  2826.     textBox = NewTextBox(left, right,
  2827.         mid - EDITBOXHEIGHT / 2, 
  2828.         mid + EDITBOXHEIGHT / 2,
  2829.         EDITABLE + WITH_PIT + ONE_LINE, "Default Extension", var ? GetString(var) : "");
  2830.     SetVar(textBox, PARENT, panel);
  2831.     PrefixList(contents, textBox);
  2832.     AssocDirectControlWithVar(textBox, fileReader, EXTENSION);
  2833.     SetVar(textBox, HELPSTRING, 
  2834.        NewString("This text box shows the default file extension, or the portion \
  2835. of the file name after the last period, for files \
  2836. which use this format.  If you change it to another extension, the new extension \
  2837. will be used when you open new file windows.  The period is implied; do not include \
  2838. it in the new file extension."));
  2839.  
  2840.     top += MINORBORDER;
  2841.  
  2842.     /*Now put in a Save All Settings button*/
  2843.     GetTemplateBounds(SettingsTemplate, "Save All Settings", &l, &r, &b, &t);
  2844.     button = NewButton(l, r, top, top + (t - b), "Save All Settings");
  2845.     top = top + (t - b) + MINORBORDER;
  2846.     PrefixList(contents, button);
  2847.     SetVar(button, PARENT, panel);
  2848.     SetVar(button, REPOBJ, fileReader);
  2849.     SetVar(button, HELPSTRING, NewString("Press this button to save all \
  2850. the settings for this file reader to a disk file.\n\n\
  2851. Settings are saved in a subdirectory named .scianSettings in your home directory.  \
  2852. If that directory does not exist, it will automatically be created.  Settings are \
  2853. saved in a file with a name of the form <name>.filrdr where <name> is the name of \
  2854. the object (with spaces converted to underscores)."));
  2855.     ActivateButton(button, false);
  2856.     list = AssembleSnapVars(fileReader);
  2857.     if (list)
  2858.     {
  2859.         ThingListPtr runner;
  2860.  
  2861.         runner = LISTOF(list);
  2862.         while (runner)
  2863.         {
  2864.         NameTyp symbolID;
  2865.  
  2866.         symbolID = GetSymbolID(runner -> thing);
  2867.         DeclareIndirectDependency(button, APPEARANCE, REPOBJ, symbolID);
  2868.             
  2869.         runner = runner -> next;
  2870.         }
  2871.     }
  2872.     SetVar(button, APPEARANCE, ObjTrue);
  2873.     SetMethod(button, APPEARANCE, MakeSaveButtonAppearance);
  2874.     SetMethod(button, CHANGEDVALUE, SaveButtonChanged);
  2875.  
  2876.     left = bottom = 0;
  2877.     right = MAX(MAJORBORDER + FROVERALLWIDTH, contentsRight) + MAJORBORDER;
  2878.  
  2879.     /*Finally, make the window around the panel*/
  2880.     Set2DIntBounds(panel, left, right, bottom, top);
  2881.     controlWindow = GetDialog((WinInfoPtr) fileReader, NewString("Controls"), windowName, 
  2882.         right, top, right, top, WINUI + WINFIXEDSIZE);    
  2883.     contents = GetVar((ObjPtr) controlWindow, CONTENTS);
  2884.     PrefixList(contents, panel);
  2885.     SetVar(panel, PARENT, (ObjPtr) controlWindow);
  2886.     SetVar((ObjPtr) controlWindow, HELPSTRING, 
  2887.         NewString("This window shows controls for an individual file reader.  \
  2888. Use Help in Context to get help on each control."));
  2889.     }
  2890.     else
  2891.     {
  2892.     PopWindow(dialogExists);
  2893.     }
  2894. }
  2895.  
  2896.  
  2897. ObjPtr MakeReaderIconHelp(readerIcon, class)
  2898. ObjPtr readerIcon, class;
  2899. /*Makes help for a file reader icon*/
  2900. {
  2901.     ObjPtr retVal, additionalHelp;
  2902.     ObjPtr repObj;
  2903.     ObjPtr var;
  2904.  
  2905.     repObj = GetVar(readerIcon, REPOBJ);
  2906.     if (!repObj)
  2907.     {
  2908.     return NULLOBJ;
  2909.     }
  2910.     var = GetVar(repObj, NAME);
  2911.  
  2912.     sprintf(tempStr, "This icon represents the %s file reader.  ",
  2913.         var ? GetString(var) : "");
  2914.     retVal = NewString(tempStr);
  2915.     additionalHelp = GetVar(repObj, HELPSTRING);
  2916.     if (!additionalHelp)
  2917.     {
  2918.     additionalHelp = NewString("For more information on this file reader, see the User Manual.");
  2919.     }
  2920.     retVal = ConcatStrings(retVal, additionalHelp);
  2921.     SetVar(class, HELPSTRING, retVal);
  2922.     return retVal;
  2923. }
  2924.  
  2925. static ObjPtr AddHDFControls(fileReader, panelContents)
  2926. ObjPtr fileReader, panelContents;
  2927. /*Adds controls appropriate to an HDF fileReader*/
  2928. {
  2929.     ObjPtr titleBox, radio, checkBox, button;
  2930.     int left, right, bottom, top;
  2931.     ObjPtr var;
  2932.  
  2933.     left = MAJORBORDER;
  2934.     bottom = MAJORBORDER;
  2935.  
  2936.     /*Do the read vectors check box*/
  2937.     right = left + HDFVECTORWIDTH;
  2938.     top = bottom + CHECKBOXHEIGHT;
  2939.  
  2940.     checkBox = NewCheckBox(left, right, bottom, top, "Read 2- and 3-Vector Data",
  2941.         GetPredicate(fileReader, READVECTOR));
  2942.     PrefixList(panelContents, checkBox);
  2943.     SetVar(checkBox, PARENT, panelContents);
  2944.     SetVar(checkBox, HELPSTRING, NewString("This controls whether the HDF reader \
  2945. will automatically read vector data with 2 and 3 dimensions.  If it is checked, \
  2946. whenever the first dimension of the dataset is either 2 or 3, it will \
  2947. be interpreted as containing 2- or 3-vector data.  The first component is in the X \
  2948. direction, the second in the Y direction, and the third in the Z direction.  \
  2949. If the box is not checked, the data will be read in as scalar data.\n\
  2950. \n\
  2951. For example, say you have a 3-D velocity field (40 by 50 by 60), where the velocity \
  2952. has three cartesian components.  Store it as an HDF dataset 40 by 50 by 60 by 3.  \
  2953. To store the velocity at (23, 37, 42), for example, put the X component at (1, 23, \
  2954. 37, 42), the Y component at (2, 23, 37, 42), and the Z component at (3, 23, 37, 42).  \
  2955. (This example uses FORTRAN conventions; a C example would go from 0 to 2 instead.)\n\
  2956. \n\
  2957. You may, if you like, use the last dimension instead of the first to specify the components \
  2958. of the vector."));
  2959.     AssocDirectControlWithVar(checkBox, fileReader, READVECTOR);
  2960.  
  2961.     bottom = top + MINORBORDER;
  2962.  
  2963.     top = bottom + CHECKBOXHEIGHT;
  2964.  
  2965.     checkBox = NewCheckBox(left, right, bottom, top, "Wrap Polar Coordinates",
  2966.         GetPredicate(fileReader, WRAPPOLAR));
  2967.     if (!GetVar(fileReader, WRAPPOLAR)) SetVar(fileReader, WRAPPOLAR, ObjTrue);
  2968.     PrefixList(panelContents, checkBox);
  2969.     SetVar(checkBox, PARENT, panelContents);
  2970.     SetVar(checkBox, HELPSTRING, NewString("This controls whether the HDF reader \
  2971. will automatically wrap scales in polar or spherical coordinates when reading the dataset.  When it \
  2972. is off, the scales along the axes will be used as is.  We recommend that you always \
  2973. leave this check box on.  \n\n\
  2974. This option is needed because most SciAn visualization objects expect the data to \
  2975. be defined over a topologically continuous grid and convert spherical coordinates \
  2976. to Mercator projection by default.  If SciAn sees a sequence along a scale \
  2977. such as 178, 179, -180, -179, there is a discontinuity between 179 and -180.  \
  2978. Even though this sequence is continuous in spherical coordinates, it is discontinuous \
  2979. in the Mercator projection.  When the check box is on, a sequence like this will \
  2980. automatically be converted to 178, 179, 180, 181.  When SciAn is enhanced to do spherical \
  2981. coordinates natively, both ways will work.\n\n\
  2982. In order for this check box to have any effect, the coordinate system in the DFSDsetdatastrs \
  2983. call must be spherical or polar and the units along each axis as specified in the \
  2984. DFSDsetdimstrs call must be degrees or units.  Upper or lower case doesn't matter."));
  2985.     AssocDirectControlWithVar(checkBox, fileReader, WRAPPOLAR);
  2986.  
  2987.     bottom = top + MINORBORDER;
  2988.  
  2989.     top = bottom + CHECKBOXHEIGHT;
  2990.  
  2991.     checkBox = NewCheckBox(left, right, bottom, top, "Compress Data",
  2992.         GetPredicate(fileReader, COMPRESSDATA));
  2993.     if (!GetVar(fileReader, COMPRESSDATA)) SetVar(fileReader, COMPRESSDATA, ObjFalse);
  2994.     PrefixList(panelContents, checkBox);
  2995.     SetVar(checkBox, PARENT, panelContents);
  2996.     SetVar(checkBox, HELPSTRING, NewString("This controls whether the HDF reader \
  2997. will store the data in compressed form.  In compressed form, only one byte is used \
  2998. to store each numerical value.  Compressed form takes only 1/4 as much space \
  2999. as normal, with an associated loss in precision.  If the minimum and maximum \
  3000. are set within the file, they are used to determine the comrpession mapping.  \
  3001. Otherwise, the minimum and maximum are determined from looking at the data."));
  3002.     AssocDirectControlWithVar(checkBox, fileReader, COMPRESSDATA);
  3003.  
  3004.     bottom = top + MINORBORDER;
  3005.  
  3006.     top = bottom + CHECKBOXHEIGHT;
  3007.  
  3008.     checkBox = NewCheckBox(left, right, bottom, top, "Read Axis Names",
  3009.         GetPredicate(fileReader, BOTHERWITHAXES));
  3010.     if (!GetVar(fileReader, BOTHERWITHAXES)) SetVar(fileReader, BOTHERWITHAXES, ObjFalse);
  3011.     PrefixList(panelContents, checkBox);
  3012.     SetVar(checkBox, PARENT, panelContents);
  3013.     SetVar(checkBox, HELPSTRING, NewString("This controls whether the HDF reader \
  3014. will read the names of the axes from the HDF file.  If it is checked, the names \
  3015. of the axes as set using the DFSDsetdimstrs will be read and interpreted as axis names.  \
  3016. If it is not checked, the first axis will be assumed to be X, the second Y, and the third Z.  \
  3017. If you don't use the DFSDsetdimstrs routine, you should keep this check box off, or else \
  3018. you will see warning messages and the occasional crash of SciAn due to a bug \
  3019. in NCSA's HDF routines.\n\n\
  3020. The axis names X, Y, and Z are recognized automatically.  You can set up additional axes by putting a \
  3021. file named .scianAxes in your home directory.  Upper or lower case doesn't matter.  Here is an example .scianAxes file \
  3022. containing definitions for Longitude and Latitude:\n\
  3023. \n#Axes file containing supplemental axes to SciAn\n\
  3024. Longitude = X\n\
  3025. Latitude = Y"));
  3026.  
  3027.     AssocDirectControlWithVar(checkBox, fileReader, BOTHERWITHAXES);
  3028.  
  3029.     bottom = top + MINORBORDER;
  3030.  
  3031.     /*Do the title box around the radio group*/
  3032.     right = left + 2 * MINORBORDER + HDFRADIOWIDTH;
  3033.     top = bottom + 2 * MINORBORDER + 2 * CHECKBOXSPACING + 3 * CHECKBOXHEIGHT + TITLEBOXTOP;
  3034.  
  3035.     titleBox = NewTitleBox(left, right, bottom, top, "Handle Out-of-Bounds Data");
  3036.     PrefixList(panelContents, titleBox);
  3037.     SetVar(titleBox, PARENT, panelContents);
  3038.  
  3039.     /*Make the radio buttons*/
  3040.     radio = NewRadioButtonGroup("Out of Bounds Radio");
  3041.     SetVar(radio, PARENT, panelContents);
  3042.     SetVar(radio, REPOBJ, fileReader);
  3043.     PrefixList(panelContents, radio);
  3044.  
  3045.     left += MINORBORDER;
  3046.     right -= MINORBORDER;
  3047.     top -= TITLEBOXTOP + MINORBORDER;
  3048.     bottom = top - CHECKBOXHEIGHT;
  3049.     button = NewRadioButton(left, right, bottom, top, "Treat as missing");
  3050.     AddRadioButton(radio, button);
  3051.     SetVar(button, HELPSTRING, NewString("When this button is down, values in \
  3052. the dataset which are out of bounds are treated as missing data."));
  3053.  
  3054.     top = bottom - CHECKBOXSPACING;
  3055.     bottom = top - CHECKBOXHEIGHT;
  3056.     button = NewRadioButton(left, right, bottom, top, "Clip to bounds");
  3057.     AddRadioButton(radio, button);
  3058.     SetVar(button, HELPSTRING, NewString("When this button is down, values in \
  3059. the dataset which are out of bounds are clipped to the bounds."));
  3060.  
  3061.     top = bottom - CHECKBOXSPACING;
  3062.     bottom = top - CHECKBOXHEIGHT;
  3063.     button = NewRadioButton(left, right, bottom, top, "Use as is");
  3064.     AddRadioButton(radio, button);
  3065.     SetVar(button, HELPSTRING, NewString("When this button is down, values in \
  3066. the dataset which are out of bounds are used as ordinary data values."));
  3067.  
  3068.     
  3069.     var = GetIntVar("AddHDFControls", fileReader, OUTOFBOUNDS);
  3070.     if (!var) SetVar(fileReader, OUTOFBOUNDS, NewInt(0));
  3071.     AssocDirectControlWithVar(radio, fileReader, OUTOFBOUNDS);
  3072.     SetVar(radio, HELPSTRING, NewString("This radio button group controls how values \
  3073. in the dataset which are out of bounds are treated.  A data value is considered \
  3074. out of bounds if it is outside the range given by the minimum and maximum, \
  3075. as specified by the DFSDSetMinMax HDF call.  If no minimum and maximum have \
  3076. been set, this radio button group has no effect."));
  3077.  
  3078.     return ObjTrue;
  3079. }
  3080.  
  3081. #ifdef PROTO
  3082. void ReadObjectControls(ObjPtr object, ObjPtr directory, Bool cpNeeded)
  3083. #else
  3084. void ReadObjectControls(object, directory, cpNeeded)
  3085. ObjPtr object, directory;
  3086. Bool cpNeeded;
  3087. #endif
  3088. /*Sets an object's controls from a possibly existing file within directory
  3089.   cpNeeded true iff a control panel is needed*/
  3090. {
  3091.     char oldDir[401];
  3092.     ObjPtr name;
  3093.     char *runner;
  3094.     ObjPtr extension;
  3095.     FILE *temp;
  3096.  
  3097.     getcwd(oldDir, 400);
  3098.     if (directory)
  3099.     {
  3100.     chdir(GetString(directory));
  3101.     }
  3102.     name = GetVar(object, NAME);
  3103.     if (!name)
  3104.     {
  3105.     return;
  3106.     }
  3107.     strcpy(tempStr, GetString(name));
  3108.  
  3109.     /*Modify file name*/
  3110.     runner = tempStr;
  3111.     while (*runner)
  3112.     {
  3113.     if (*runner == ' ') *runner = '_';
  3114.     ++runner;
  3115.     }
  3116.     extension = GetVar(object, SAVEEXTENSION);
  3117.     if (extension)
  3118.     {
  3119.     strcat(runner, ".");
  3120.     strcat(runner, GetString(extension));
  3121.     }
  3122.  
  3123.     SetVar(object, DIRECTORY, directory);
  3124.  
  3125.     if (temp = fopen(tempStr, "r"))
  3126.     {
  3127.     /*Read the file into the object's control panel*/
  3128.     Bool oldShowControlPanels;
  3129.     Bool oldSettingUp;
  3130.     ObjPtr controlWindow;
  3131.     WinInfoPtr oldScriptWindow;
  3132.     WinInfoPtr oldSelWinInfo;
  3133.  
  3134.     fclose(temp);
  3135.  
  3136.     oldSelWinInfo = selWinInfo;
  3137.  
  3138.     InhibitLogging(true);
  3139.     if (cpNeeded)
  3140.     {
  3141.         oldShowControlPanels = showControlPanels;
  3142.         oldScriptWindow = scriptWindow;
  3143.         showControlPanels = false;
  3144.  
  3145.         /*Show and create the control panel*/
  3146.         scriptWindow = (WinInfoPtr) NewControlWindow(object);
  3147.     }
  3148.  
  3149.  
  3150.     oldSettingUp = settingUp;
  3151.     settingUp = true;
  3152.     BeginScript(tempStr);
  3153.     while(ReadScriptLine());
  3154.     settingUp = oldSettingUp;
  3155.  
  3156.     if (cpNeeded)
  3157.     {
  3158.         showControlPanels = oldShowControlPanels;
  3159.         scriptWindow = oldScriptWindow;
  3160.         selWinInfo = oldSelWinInfo;
  3161.     }
  3162.     InhibitLogging(false);
  3163.     }
  3164.  
  3165.     chdir(oldDir);
  3166. }
  3167.  
  3168. void SaveObjectControls(object, directory)
  3169. ObjPtr object, directory;
  3170. /*Sets an object's controls from a possibly existing file within directory,
  3171.   or in the home directory if directory is null*/
  3172. {
  3173.     char oldDir[401], fileName[401];
  3174.     ObjPtr name;
  3175.     char *runner;
  3176.     ObjPtr extension;
  3177.  
  3178.     getcwd(oldDir, 400);
  3179.     if (directory)
  3180.     {
  3181.     chdir(GetString(directory));
  3182.     }
  3183.     name = GetVar(object, NAME);
  3184.     if (!name)
  3185.     {
  3186.     return;
  3187.     }
  3188.     strcpy(fileName, GetString(name));
  3189.  
  3190.     /*Modify file name*/
  3191.     runner = fileName;
  3192.     while (*runner)
  3193.     {
  3194.     if (*runner == ' ') *runner = '_';
  3195.     ++runner;
  3196.     }
  3197.     extension = GetVar(object, SAVEEXTENSION);
  3198.     if (extension)
  3199.     {
  3200.     strcat(runner, ".");
  3201.     strcat(runner, GetString(extension));
  3202.     }
  3203.  
  3204.     InhibitLogging(true);
  3205.     if (OpenLogFile(fileName))
  3206.     {
  3207.     /*Read the file into the object's control panel*/
  3208.     FuncTyp method;
  3209.     Bool oldShowControlPanels, oldSettingUp;
  3210.  
  3211.     LogNoWindow("# Saved settings for ");
  3212.     LogNoWindow(GetString(name));
  3213.     LogNoWindow("\n");
  3214.  
  3215.     oldSettingUp = settingUp;
  3216.     oldShowControlPanels = showControlPanels;
  3217.  
  3218.     settingUp = true;
  3219.     showControlPanels = false;
  3220.  
  3221.     method = GetMethod(object, SAVEALLCONTROLS);
  3222.     if (method)
  3223.     {
  3224.         (*method)(object);
  3225.     }
  3226.     showControlPanels = oldShowControlPanels;
  3227.     settingUp = oldSettingUp;
  3228.  
  3229.     CloseLogFile();
  3230.     }
  3231.     InhibitLogging(false);
  3232.  
  3233.     chdir(oldDir);
  3234. }
  3235.  
  3236. void DoSaveObject()
  3237. /*Saves the object whose controls are on the top window*/
  3238. {
  3239.     if (selWinInfo)
  3240.     {
  3241.     ObjPtr repObj;
  3242.     repObj = GetVar((ObjPtr) selWinInfo, REPOBJ);
  3243.     if (repObj)
  3244.     {
  3245.         Log("save controls");
  3246.         DeferMessage(repObj, SAVECPANEL);
  3247.     }
  3248.     }
  3249. }
  3250.  
  3251. /*Fixed format data reading helpers*/
  3252.  
  3253. #ifdef PROTO
  3254. Bool GetFString(char *d, char *s, int beg, int end)
  3255. #else
  3256. Bool GetFString(d, s, beg, end)
  3257. char *d;
  3258. char *s;
  3259. int beg;
  3260. int end;
  3261. #endif
  3262. /*Puts into d a string from beg to end in s.  Beg and end start at 1, not 0*/
  3263. {
  3264.     int k;
  3265.  
  3266.     for (k = beg - 1; k <= end - 1; ++k)
  3267.     {
  3268.     *d++ = s[k];
  3269.     }
  3270.     *d = 0;
  3271.     return true;
  3272. }
  3273.  
  3274. #ifdef PROTO
  3275. Bool GetFLong(long *d, char *s, int beg, int end)
  3276. #else
  3277. Bool GetFLong(d, s, beg, end)
  3278. long *d;
  3279. char *s;
  3280. int beg;
  3281. int end;
  3282. #endif
  3283. {
  3284.     int k;
  3285.     char buffer[256];
  3286.  
  3287.     for (k = 0; k <= end - beg; ++k)
  3288.     {
  3289.     buffer[k] = s[beg + k - 1];
  3290.     }
  3291.     buffer[k] = '\0';
  3292.  
  3293.     return sscanf(buffer, "%ld", d) ? true : false;
  3294. }
  3295.  
  3296. #ifdef PROTO
  3297. Bool GetFReal(real *d, char *s, int beg, int end)
  3298. #else
  3299. Bool GetFReal(d, s, beg, end)
  3300. real *d;
  3301. char *s;
  3302. int beg;
  3303. int end;
  3304. #endif
  3305. {
  3306.     int k;
  3307.     char buffer[256];
  3308.  
  3309.     for (k = 0; k <= end - beg; ++k)
  3310.     {
  3311.     buffer[k] = s[beg + k - 1];
  3312.     }
  3313.     buffer[k] = '\0';
  3314.  
  3315.     return sscanf(buffer, "%g", d) ? true : false;
  3316. }
  3317.  
  3318. TextBuf *NewTextBuf()
  3319. /*Returns a new text buffer*/
  3320. {
  3321.     TextBuf *retVal;
  3322.     retVal = (TextBuf *) Alloc(sizeof(TextBuf));
  3323.     retVal -> builtTextLength = ALLOCTEXTBUF;
  3324.     retVal -> builtText = Alloc(ALLOCTEXTBUF);
  3325.     retVal -> builtText[0] = 0;
  3326.     retVal -> lastChar = 0;
  3327.     return retVal;
  3328. }
  3329.  
  3330. #ifdef PROTO
  3331. void AppendTextChar(TextBuf *buf, char c)
  3332. #else
  3333. void AppendTextChar(TextBuf *buf, char c)
  3334. TextBuf *buf;
  3335. char c;
  3336. #endif
  3337. /*Appends a single char to buf*/
  3338. {
  3339.     buf -> builtText[buf -> lastChar] = c;
  3340.     ++(buf -> lastChar);
  3341.     if (buf -> lastChar >= buf -> builtTextLength)
  3342.     {
  3343.     buf -> builtTextLength += ALLOCTEXTBUF;
  3344.     buf -> builtText = Realloc(buf -> builtText, buf -> builtTextLength);
  3345.     }
  3346.     buf -> builtText[buf -> lastChar] = 0;
  3347. }
  3348.  
  3349. #ifdef PROTO
  3350. void SmartAppendTextLine(TextBuf *buf, char *line)
  3351. #else
  3352. void SmartAppendTextLine(buf, line)
  3353. TextBuf *buf;
  3354. char *line;
  3355. #endif
  3356. /*Appends line to the text in buf.  Maybe should do some thinking to justify
  3357.   the word "smart."  Basically, line is supposed to be a line formatted for
  3358.   a teletype, and this is supposed to figure out some way to deal with the
  3359.   problem of formatting it into a text box.*/
  3360. {
  3361.     int k;
  3362.  
  3363.     /*Find the end of the string and trim it down to the last non-space char*/
  3364.  
  3365.     k = strlen(line);
  3366.     if (k) --k;
  3367.     while (k && isspace(line[k])) --k;
  3368.     if (!k)
  3369.     {
  3370.     /*Just an end of line*/
  3371.     }
  3372.     else
  3373.     {
  3374.     int i;
  3375.     /*There is some text.*/
  3376.     for (i = 0; i <= k; ++i)
  3377.     {
  3378.         AppendTextChar(buf, line[i]);
  3379.     }
  3380.     }
  3381.     AppendTextChar(buf, '\n');
  3382. }
  3383.  
  3384. #ifdef PROTO
  3385. char *GetBuiltText(TextBuf *buf)
  3386. #else
  3387. char *GetBuiltText(buf)
  3388. TextBuf *buf;
  3389. #endif
  3390. /*Gets the built text from the buffer*/
  3391. {
  3392.     return buf -> builtText;
  3393. }
  3394.  
  3395. #ifdef PROTO
  3396. void DisposeTextBuf(TextBuf *buf)
  3397. #else
  3398. void DisposeTextBuf(buf)
  3399. TextBuf *buf;
  3400. #endif
  3401. {
  3402.     if (!buf) return;
  3403.     Free(buf -> builtText);
  3404.     Free(buf);
  3405. }
  3406.  
  3407. #define ALLOCATOMS    100        /*Number of atoms to allocate at one time*/
  3408.  
  3409. #ifdef PROTO
  3410. void Titleize(char *s)
  3411. #else
  3412. void Titleize(s)
  3413. char *s;
  3414. #endif
  3415. /*Capitalizes a character string, sort of like a title*/
  3416. {
  3417.     Bool readyForCapital = true;
  3418.  
  3419.     while (*s)
  3420.     {
  3421.     if (isalpha(*s))
  3422.     {
  3423.         if (readyForCapital)
  3424.         {
  3425.         *s = toupper(*s);
  3426.         readyForCapital = false;
  3427.         }
  3428.         else
  3429.         {
  3430.         *s = tolower(*s);
  3431.         }
  3432.     }
  3433.     else if (!isdigit(*s))
  3434.     {
  3435.         readyForCapital = true;
  3436.     }
  3437.     ++s;
  3438.     }
  3439. }
  3440.  
  3441. #ifndef RELEASE
  3442. static ObjPtr FiddleData(dataset)
  3443. ObjPtr dataset;
  3444. /*Fiddles the data in the dataset*/
  3445. {
  3446.     SetVar(dataset, DATA, GetVar(dataset, DATA));
  3447.     DeferMessage(dataset, MARKTIME);
  3448.     DatasetChanged(dataset);
  3449.     return ObjTrue;
  3450. }
  3451.  
  3452. static ObjPtr DiddleData(dataset)
  3453. ObjPtr dataset;
  3454. /*Diddles the data in the dataset based on shared memory*/
  3455. {
  3456.     real *address;
  3457.     ObjPtr x, y, z;
  3458.     real *xel, *yel, *zel;
  3459.     int k;
  3460.     ObjPtr var;
  3461.     long dim;
  3462.  
  3463.     var = GetIntVar("DiddleData", dataset, SHMADDRESS);
  3464.     if (!var) return ObjFalse;
  3465.     address = (real *) GetInt(var);
  3466.  
  3467.     var = GetRealVar("DiddleData", dataset, SHMSEMAPHORE);
  3468.     if (!var) return ObjFalse;
  3469.  
  3470.     DeferMessage(dataset, MARKTIME);
  3471.  
  3472.     if (GetReal(var) == *address)
  3473.     {
  3474.     /*Hasn't changed*/
  3475.     return ObjTrue;
  3476.     }
  3477.     SetVar(dataset, SHMSEMAPHORE, NewReal(*address));
  3478.  
  3479.     var = GetVar(dataset, DATA);
  3480.     if (!var)
  3481.     {
  3482.     return ObjFalse;
  3483.     }
  3484.  
  3485.     x = ((ObjPtr *) ELEMENTS(var))[0];
  3486.     y = ((ObjPtr *) ELEMENTS(var))[1];
  3487.     z = ((ObjPtr *) ELEMENTS(var))[2];
  3488.  
  3489.     xel = ELEMENTS(x);
  3490.     yel = ELEMENTS(y);
  3491.     zel = ELEMENTS(z);
  3492.  
  3493.     dim = DIMS(x)[0];
  3494.  
  3495.     for (k = 0; k < dim; ++k)
  3496.     {
  3497.     xel[k] = address[1 + k * 3];
  3498.     yel[k] = address[2 + k * 3];
  3499.     zel[k] = address[3 + k * 3];
  3500.     }
  3501.  
  3502.     SetVar(dataset, DATA, var);
  3503.     DatasetChanged(dataset);
  3504.     return ObjTrue;
  3505. }
  3506.  
  3507. static ObjPtr DiddleTimestep(dataset)
  3508. ObjPtr dataset;
  3509. /*Diddles the timestep in the dataset based on shared memory*/
  3510. {
  3511.     real *address;
  3512.     ObjPtr x, y, z;
  3513.     real *xel, *yel, *zel;
  3514.     int k;
  3515.     ObjPtr var;
  3516.     long dim;
  3517.  
  3518.     var = GetIntVar("DiddleData", dataset, SHMADDRESS);
  3519.     if (!var) return ObjFalse;
  3520.     address = (real *) GetInt(var);
  3521.  
  3522.     var = GetRealVar("DiddleData", dataset, SHMSEMAPHORE);
  3523.     if (!var) return ObjFalse;
  3524.  
  3525.     DeferMessage(dataset, MARKTIME);
  3526.  
  3527.     if (GetReal(var) == *address)
  3528.     {
  3529.     /*Hasn't changed*/
  3530.     return ObjTrue;
  3531.     }
  3532.     SetVar(dataset, SHMSEMAPHORE, NewReal(*address));
  3533.  
  3534.     var = GetVar(dataset, DATA);
  3535.     if (!var)
  3536.     {
  3537.     return ObjFalse;
  3538.     }
  3539.     ((real *) ELEMENTS(var))[0] = *address;
  3540.  
  3541.     SetVar(dataset, DATA, var);
  3542.     DatasetChanged(dataset);
  3543.     return ObjTrue;
  3544. }
  3545.  
  3546. static ObjPtr MakeWigglyMoleculeCurData(dataset)
  3547. ObjPtr dataset;
  3548. /*Makes the curdata of a wiggly molecule*/
  3549. {
  3550.     register ObjPtr oldData, newData;
  3551.     register ObjPtr *components;
  3552.     register real *ox, *oy, *oz, *nx, *ny, *nz;
  3553.     register long k;
  3554.     register long dim;
  3555.     register real r;
  3556.     long temp;
  3557.  
  3558.  
  3559.     /*Get the old data*/
  3560.     oldData = GetVar(dataset, DATA);
  3561.     components = ELEMENTS(oldData);
  3562.     dim = DIMS(components[0])[0];
  3563.     ox = ELEMENTS(components[0]);
  3564.     oy = ELEMENTS(components[1]);
  3565.     oz = ELEMENTS(components[2]);
  3566.     
  3567.     temp = 3;
  3568.     newData = NewArray(AT_OBJECT, 1, &temp);
  3569.     components = ELEMENTS(newData);
  3570.     components[0] = NewRealArray(1, dim);
  3571.     components[1] = NewRealArray(1, dim);
  3572.     components[2] = NewRealArray(1, dim);
  3573.     nx = ELEMENTS(components[0]);
  3574.     ny = ELEMENTS(components[1]);
  3575.     nz = ELEMENTS(components[2]);
  3576.  
  3577.     for (k = 0; k < dim; ++k)
  3578.     {
  3579.     r = ((real) (random() % 100 - 50)) / 150.0;
  3580.     nx[k] = ox[k] + r;
  3581.     r = ((real) (random() % 100 - 50)) / 150.0;
  3582.     ny[k] = oy[k] + r;
  3583.     r = ((real) (random() % 100 - 50)) / 150.0;
  3584.     nz[k] = oz[k] + r;
  3585.     }
  3586.  
  3587.     SetVar(dataset, DATA, newData);
  3588.     return ObjTrue;
  3589. }
  3590. #endif
  3591.  
  3592.  
  3593. /***************************begin getAtomNum***********************************/
  3594.  
  3595. /* 
  3596.    Tzong-Yow Hwu, 6/10/1993 
  3597.    7/09/1993, revised by distinguishing among 
  3598.               Regular Atom:  atoms belong to ATOM record
  3599.                              this is further distinguished between
  3600.                              1. amino acid residue atom,
  3601.                              2. nucleic acid residue atom, and
  3602.                              3. others. 
  3603.               Nonstandard Atom:  atoms of HETATM record
  3604.  
  3605.   parseAtomName returns the atomic number of atomName and store the
  3606.   remoteness indicator in remoteness. It returns 0 if unable to 
  3607.   recognize the atomName ,or for atoms of ambiguity (whose symbol is A).  
  3608.   It stores '\0' in remoteness if unable to recognize the
  3609.   remoteness indicator or if no remoteness indicator found in atomName.
  3610.   Legitimate remoteness indicators are A, B, G, D, E, Z, H, T, U, F, X, Q, 
  3611.   and W. 
  3612.  
  3613.   atomName string format:
  3614.  
  3615.   ATOM record
  3616.   1. amino acid residue atom:
  3617.  
  3618.      standard:  the atomName string is four character long.
  3619.           Characters 1-2 are for chemical symbols(right justified),
  3620.           character 3 is a remoteness indicator(alphabetic), and
  3621.           character 4 is a branch designator(numeric.)
  3622.      exceptions: 1. Atoms for which some ambiguity exists in the
  3623.                     crystallographic results are designated A.  
  3624.                  2. The extra oxygen atom of the carboxy terminal amino acid is
  3625.                 designated OXT.
  3626.                  3. When more than one hydrogen atoms are bounded to a single
  3627.                 non-hydrogen atom, branch designator is required to be the
  3628.              first char.  Not necessarily followed, some heurestic rules
  3629.                     used.
  3630.   2. nucleic acid residue atom:
  3631.  
  3632.      1. generally no remoteness indicator. (?)
  3633.      2. char 1-2 are for atom symbols.
  3634.         char 3-4 for atom position ,and '*' or '''
  3635.      3. OXT for the oxygen atom at free 5' phosphate terminus.
  3636.  
  3637.   3. other residue atom:
  3638.      
  3639.      parse it according to nucleic acid residue atom.
  3640.  
  3641.  
  3642.   HETATM record
  3643.      1. Generally, the 2nd char is used for atom symbol. 
  3644.         The 1st char is sometimes used for other purpose such as AO9, PC5,...
  3645.         etc. in COENZYME A, and AP, AN9, AC2*, ...etc. in NAD group.  But 
  3646.         watch out for atom symbols of two char long, such as FE, CA, ZN,
  3647.     PB, MG, CL, BR, CU, NA...etc.
  3648.      2. If there is a remoteness indicator, it would appear as the 3rd char.
  3649.         But the 3rd char is not always a remoteness indicator.  Take the 3rd
  3650.         char as a remoteness indicator if it matches one the remoteness symbols.
  3651.         The " NA4" and " NA2" of the METHOTREXATE group may be treated wrong
  3652.         under the assumption. (?)
  3653. #include "ScianPeriodicTable.h"
  3654.  */
  3655.  
  3656.  
  3657. #ifdef PROTO
  3658. int getAtomNum(const char *record, char *remoteness);
  3659. #else
  3660. int getAtomNum();
  3661. #endif
  3662.  
  3663. #ifdef PROTO
  3664. int getAtomNum(const char *record, char *remoteness)
  3665. #else
  3666. int getAtomNum(record, remoteness)
  3667. const char *record;
  3668. char *remoteness;
  3669. #endif
  3670. {
  3671.   char *aminoAcidResidueAbbre[] = 
  3672.          {
  3673.            "ABU", "ACD", "ALA", "ALB", "ALI", "ARG", "ARO", "ASN", "ASP", "ASX",
  3674.            "BAS",
  3675.            "CYS",
  3676.            "GLN", "GLU", "GLX", "GLY", 
  3677.            "HIS", "HYP",
  3678.            "ILE",
  3679.            "LEU", "LYS",
  3680.            "MET", 
  3681.            "PCA", "PHE", "PRO",
  3682.            "SAR", "SER", 
  3683.            "THR", "TRP", "TYR",
  3684.            "VAL"
  3685.          };
  3686.   const int numAminoAbbre = 31;
  3687.   char atomType[7], atomName[5], residueName[4], atomSym[3];
  3688.   char s[132];
  3689.   int atomicNumber;
  3690.   int i;
  3691.  
  3692.   char remotenessSyms[] = 
  3693.          {'A', 'B', 'G', 'D', 'E', 'Z', 'H', 'T', 'U', 'F', 'X', 'Q', 'W'};
  3694.   const int numRemoteSyms = 13;
  3695. #undef VERIFYREMOTE 
  3696. #define VERIFYREMOTE(a)\
  3697. {\
  3698.   int j;\
  3699.   for (j = 0;\
  3700.        j < numRemoteSyms && a != remotenessSyms[j];\
  3701.        j++) ;\
  3702.   if (j == numRemoteSyms)\
  3703.     {\
  3704.       a = '\0';\
  3705.     }\
  3706. }
  3707.  
  3708.   /* get atomType, atomName, and residueName from record */
  3709.   for (i = 0; i < 6; i++)
  3710.      {
  3711.        atomType[i] = toupper(record[i]);
  3712.      }
  3713.   atomType[i] = '\0';
  3714.   for (i = 0; i < 4; i++)
  3715.      {
  3716.        atomName[i] = toupper(record[i + 12]);
  3717.      } 
  3718.   atomName[i] = '\0';
  3719.   for (i = 0; i < 3; i++)
  3720.      {
  3721.        residueName[i] = toupper(record[i + 17]);
  3722.      }
  3723.   residueName[i] = '\0';
  3724.  
  3725.   if (0 == strcmp(atomType, "ATOM  "))
  3726.     {
  3727.       /* ATOM record */
  3728.       int notAminoAcidResidue = 1;
  3729.       
  3730.       /* see if it's amino acid residue */
  3731.       for (i = 0; notAminoAcidResidue && i < numAminoAbbre; i++)
  3732.          {
  3733.            notAminoAcidResidue = strcmp(residueName, aminoAcidResidueAbbre[i]); 
  3734.          }
  3735.       if (!notAminoAcidResidue)
  3736.         {
  3737.           /* parse as amino acid residue atoms */
  3738.           if (atomName[0] == ' ')
  3739.             {
  3740.               /* then the 2nd char must be an atomic symbol */
  3741.               if (atomName[1] == 'A')
  3742.                 {
  3743.                   /* it's an atom of ambiguity, assign atomic number 0 */
  3744.                   atomicNumber = 0;
  3745.                 }
  3746.               else
  3747.                 {
  3748.                   atomSym[0] = atomName[1];
  3749.                   atomSym[1] = '\0';
  3750.                   atomicNumber = AtomNameToNumber(atomSym);
  3751.                 }
  3752.               if (atomicNumber)
  3753.                 {
  3754.                  /* see if the 3rd char is a legitimate remoteness indicator */
  3755.                  *remoteness = atomName[2];
  3756.          VERIFYREMOTE(*remoteness);
  3757.                 }
  3758.               else
  3759.                 {
  3760.                   *remoteness = '\0';
  3761.                 }
  3762.             }
  3763.           else if (isdigit(atomName[0]))
  3764.             {
  3765.               /* maybe the case of "1HB ", ...etc. */
  3766.               if (atomName[1] == 'H')
  3767.                 {
  3768.                   atomicNumber = AtomNameToNumber("H");
  3769.                  /* see if the 3rd char is a legitimate remoteness indicator */
  3770.                  *remoteness = atomName[2];
  3771.          VERIFYREMOTE(*remoteness);
  3772.                 }
  3773.               else
  3774.                 {
  3775.                   /* illegal atom name of ATOM amino acid group */
  3776.                   atomicNumber = 0;
  3777.                   *remoteness = '\0';
  3778.                 }
  3779.             }
  3780.           else if ( atomName[0] == 'H' && isdigit(atomName[2]) && 
  3781.             isdigit(atomName[3]))
  3782.             {
  3783.               /* maybe the case such as "HD22", ...etc. if the 2nd 
  3784.                  char is a legitimate remoteness indicator */
  3785.               *remoteness = atomName[1];
  3786.               VERIFYREMOTE(*remoteness);
  3787.           if (*remoteness == '\0')
  3788.                 {
  3789.           /* not legal */
  3790.                   atomicNumber = 0;
  3791.                 }
  3792.               else
  3793.                 {
  3794.                   atomicNumber = AtomNameToNumber("H");
  3795.                 }
  3796.             }
  3797.           else
  3798.             {
  3799.               /* treat the first 2 chars as atomic symbol */
  3800.               atomSym[0] = atomName[0];
  3801.               atomSym[1] = atomName[1];
  3802.               atomSym[2] = '\0';
  3803.  
  3804.               if (!(atomicNumber = AtomNameToNumber(atomSym)))
  3805.                 {
  3806.                   *remoteness = '\0';
  3807.                 }
  3808.               else
  3809.                 {
  3810.                   /* see if the 3rd char is a legitimate remoteness indicator */
  3811.                   *remoteness = atomName[2];
  3812.           VERIFYREMOTE(*remoteness);
  3813.                 }
  3814.             }
  3815.         }
  3816.       else
  3817.         {
  3818.           /* assume it's an atom of nucleic acid residue */
  3819.           /* no remoteness indicator */
  3820.           *remoteness = '\0';
  3821.           if (atomName[0] = ' ')
  3822.             {
  3823.               atomSym[0] = atomName[1];
  3824.               atomSym[1] = '\0';
  3825.             }
  3826.           else
  3827.             {
  3828.               atomSym[0] = atomName[0];
  3829.               atomSym[1] = atomName[1];
  3830.               atomSym[2] = '\0';
  3831.             }
  3832.           atomicNumber = AtomNameToNumber(atomSym);
  3833.         }
  3834.     }
  3835.   else if (0 == strcmp(atomType, "HETATM"))
  3836.     {
  3837.       /* HETATM record */
  3838.       if (atomName[0] == ' ' || isdigit(atomName[0]))
  3839.         {
  3840.           /* then the 2nd char must be an atomic symbol */
  3841.       if (atomName[1] == 'A')
  3842.         {
  3843.           /* atom of ambiquity */
  3844.           atomicNumber = 0;
  3845.         }
  3846.           else
  3847.         {
  3848.               atomSym[0] = atomName[1];
  3849.               atomSym[1] = '\0';
  3850.               atomicNumber = AtomNameToNumber(atomSym);
  3851.         }
  3852.         }
  3853.       else if (atomName[2] == '*' || atomName[3] == '*')
  3854.     {
  3855.       /* atoms of ribose, the 2nd char must be an atomic symbol */
  3856.           atomSym[0] = atomName[1];
  3857.           atomSym[1] = '\0';
  3858.           atomicNumber = AtomNameToNumber(atomSym);
  3859.     }
  3860.       else if (atomName[0] == 'A')
  3861.         {
  3862.       /* maybe 1. atoms of COENZYME A or NAD, or
  3863.            2. atoms of two chars starting with A */
  3864.       /* When the 2nd char is C, N, O, or P, it's most likely case 1 */
  3865.       if (atomName[1] == 'C' || atomName[1] == 'N' ||
  3866.           atomName[1] == 'O' || atomName[1] == 'P' )
  3867.         { 
  3868.               atomSym[0] = atomName[1];
  3869.               atomSym[1] = '\0';
  3870.             }
  3871.           else
  3872.         {
  3873.               atomSym[0] = atomName[0];
  3874.               atomSym[1] = atomName[1];
  3875.               atomSym[2] = '\0';
  3876.         }
  3877.           atomicNumber = AtomNameToNumber(atomSym);
  3878.         }
  3879.       else if (atomName[0] == 'P')
  3880.         {
  3881.       /* maybe 1. atoms of COENZYME A, or
  3882.            2. atoms of two chars starting with P */
  3883.       /* When the 2nd char is C, N, O, or S, it's most likely case 1 */
  3884.       if (atomName[1] == 'C' || atomName[1] == 'N' ||
  3885.           atomName[1] == 'O' || atomName[1] == 'S' )
  3886.         { 
  3887.               atomSym[0] = atomName[1];
  3888.               atomSym[1] = '\0';
  3889.             }
  3890.           else
  3891.         {
  3892.               atomSym[0] = atomName[0];
  3893.               atomSym[1] = atomName[1];
  3894.               atomSym[2] = '\0';
  3895.         }
  3896.           atomicNumber = AtomNameToNumber(atomSym);
  3897.         }
  3898.       else if (atomName[0] == 'N')
  3899.         {
  3900.       /* maybe 1. atoms of NAD, or
  3901.            2. atoms of two chars starting with N */
  3902.       /* When the 2nd char is C, N, O, or P, it's most likely case 1 */
  3903.       if (atomName[1] == 'C' || atomName[1] == 'N' ||
  3904.           atomName[1] == 'O' || atomName[1] == 'P' )
  3905.         { 
  3906.               atomSym[0] = atomName[1];
  3907.               atomSym[1] = '\0';
  3908.             }
  3909.           else
  3910.         {
  3911.               atomSym[0] = atomName[0];
  3912.               atomSym[1] = atomName[1];
  3913.               atomSym[2] = '\0';
  3914.         }
  3915.           atomicNumber = AtomNameToNumber(atomSym);
  3916.         }
  3917.       else
  3918.         {
  3919.       /* Otherwise, do the best it can to recognize the atom symbol */
  3920.           atomSym[0] = atomName[0];
  3921.           atomSym[1] = atomName[1];
  3922.           atomSym[2] = '\0';
  3923.           atomicNumber = AtomNameToNumber(atomSym);
  3924.       if (!atomicNumber)
  3925.         {
  3926.           atomSym[0] = atomName[1];
  3927.           atomSym[1] = '\0';
  3928.           atomicNumber = AtomNameToNumber(atomSym);
  3929.         }
  3930.         }
  3931.       if (atomicNumber)
  3932.         {
  3933.          /* see if the 3rd char is a legitimate remoteness indicator */
  3934.          *remoteness = atomName[2];
  3935.      VERIFYREMOTE(*remoteness);
  3936.         }
  3937.       else
  3938.         {
  3939.           *remoteness = '\0';
  3940.         }
  3941.     }
  3942.   else
  3943.     {
  3944.       sprintf(s, "Funny atom type %c%c%c%c%c%c", record[0], record[1], 
  3945.               record[2], record[3], record[4], record[5]);
  3946.       ReportError("getAtomNum", s);
  3947.       *remoteness = '\0';
  3948.       atomicNumber = 0;
  3949.       return atomicNumber;
  3950.     }
  3951.   
  3952.   if (!atomicNumber)
  3953.     {
  3954.       sprintf(s, "Funny atom name %c%c%c%c", record[12], record[13], 
  3955.               record[14], record[15]);
  3956.       ReportError("getAtomNum", s);
  3957.     }
  3958.   return atomicNumber;
  3959. }
  3960.  
  3961. /************* end getAtomNum******************************************************/
  3962.  
  3963. /*Atom structure for protein data bank file*/
  3964. typedef struct
  3965.     {
  3966.     real x;    
  3967.     real y;
  3968.     real z;
  3969.  
  3970.     real occupancy;
  3971.     real tempFactor;
  3972.     int atomicNumber;
  3973.     long residue;        /*Residue number*/        
  3974.     Bool isCarbonAlpha;
  3975.     } Atom;
  3976.  
  3977. #define MAKEBOND(a, b) if (nBonds >= nBondsAllocated)            \
  3978.     {if (nBondsAllocated) {nBondsAllocated += 200;            \
  3979.      bondsBuffer = (TwoReals *) Realloc(bondsBuffer,        \
  3980.         sizeof(TwoReals) * nBondsAllocated);}            \
  3981.      else {nBondsAllocated = 200;                    \
  3982.      bondsBuffer = (TwoReals *) Alloc(sizeof(TwoReals) * nBondsAllocated); }} \
  3983.      bondsBuffer[nBonds][0] = (real) (a);                \
  3984.      bondsBuffer[nBonds][1] = (real) (b);                \
  3985.      ++nBonds;
  3986.             
  3987.  
  3988. static ObjPtr ReadPDBFile(reader, fileName)
  3989. ObjPtr reader;
  3990. char *fileName;
  3991. /*Reads a Protein Data Bank file.*/
  3992. {
  3993.     char typeBuf[10];
  3994.     char noteBuf[100];
  3995.     char compoundName[100];
  3996.     Bool nameGiven = false;
  3997.     FILE *inFile;
  3998.  
  3999.     /*Go through the file*/
  4000.     inFile = fopen(fileName, "r");
  4001.     if (inFile)
  4002.     {
  4003.     /*The file exists.  Read it*/
  4004.     Atom *atoms;
  4005.     long nAtoms;
  4006.     long nAtomsAllocated;
  4007.     long k;
  4008.     real bounds[6];
  4009.     ObjPtr notes;
  4010.     TextBuf *remark;
  4011.     TextBuf *source;
  4012.     TextBuf *author;
  4013.     TextBuf *journal;
  4014.     TextBuf *expData;
  4015.     int topResidue;
  4016.     TwoReals *bondsBuffer = 0;
  4017.     long nBondsAllocated = 0;
  4018.     long nBonds = 0;
  4019.  
  4020.     /*Make the text buffers*/
  4021.     remark = 0;
  4022.     source = 0;
  4023.     author = 0;
  4024.     journal = 0;
  4025.     expData = 0;
  4026.  
  4027.  
  4028.     /*Make bounds impossible*/
  4029.     bounds[0] = bounds[2] = bounds[4] = PLUSINF;
  4030.     bounds[1] = bounds[3] = bounds[5] = MINUSINF;
  4031.  
  4032.     /*No atoms to start with*/
  4033.     nAtomsAllocated = 0;
  4034.     nAtoms = 0;
  4035.  
  4036.     topResidue = 0;
  4037.  
  4038.     while (fgets(tempStr, 100, inFile))
  4039.     {
  4040.         /*Determine the type*/
  4041.  
  4042.         if (GetFString(typeBuf, tempStr, 1, 6))
  4043.         {
  4044.         /*First check for sanity*/
  4045.         for (k = 0; k < 6; ++k)
  4046.         {
  4047.             if (!isalpha(typeBuf[k]) && !isspace(typeBuf[k]) && !isdigit(typeBuf[k]))
  4048.             {
  4049.             FileFormatError("ReadPDBFile", "This does not appear to be a valid protein data bank file");
  4050.             break;
  4051.             }
  4052.         }
  4053.  
  4054.         /*Now see what it is*/
  4055.         if ((0 == strcmp2("ATOM  ", typeBuf)) || (0 == strcmp2("HETATM", typeBuf)))
  4056.         {
  4057.             /*It's an atom*/
  4058.             real x, y, z;
  4059.             /*
  4060.             char *t;
  4061.             */
  4062.             char atomNameBuf[4];
  4063.             char atomRemoteness;
  4064.             int atomicNumber;
  4065.             Bool isCarbonAlpha;
  4066.             long atomSerialNumber;
  4067.  
  4068.             /*Get the atom serial number*/
  4069.             if (!GetFLong(&atomSerialNumber, tempStr, 7, 11))
  4070.             {
  4071.             FileFormatError("ReadPDBFile", "Missing atom serial number");
  4072.             }
  4073.             if (atomSerialNumber > nAtoms)
  4074.             {
  4075.             nAtoms = atomSerialNumber;
  4076.             }
  4077.  
  4078.             /*Make more atoms if need be*/
  4079.             if (nAtoms >= nAtomsAllocated)
  4080.             {
  4081.             if (nAtomsAllocated)
  4082.             {
  4083.                 nAtomsAllocated += ALLOCATOMS;
  4084.                 atoms = (Atom *) Realloc(atoms, sizeof(Atom) * nAtomsAllocated);
  4085.             }
  4086.             else
  4087.             {
  4088.                 nAtomsAllocated = ALLOCATOMS;
  4089.                 atoms = (Atom *) Alloc(sizeof(Atom) * nAtomsAllocated);
  4090.             }
  4091.             for (k = nAtomsAllocated - ALLOCATOMS;
  4092.                  k < nAtomsAllocated; ++k)
  4093.             {
  4094.                 atoms[k] . x = missingData;    
  4095.                 atoms[k] . y = missingData;    
  4096.                 atoms[k] . z = missingData;    
  4097.                 atoms[k] . occupancy = missingData;    
  4098.                 atoms[k] . tempFactor = missingData;    
  4099.                 atoms[k] . atomicNumber = 0;    
  4100.             }
  4101.             }
  4102.  
  4103.             /*Get the coordinates*/
  4104.             GetFReal(&(atoms[atomSerialNumber - 1] . x), tempStr, 31, 38);
  4105.             GetFReal(&(atoms[atomSerialNumber - 1] . y), tempStr, 39, 46);
  4106.             GetFReal(&(atoms[atomSerialNumber - 1] . z), tempStr, 47, 54);
  4107.  
  4108.             if (atoms[atomSerialNumber - 1] . x < bounds[0]) bounds[0] = atoms[atomSerialNumber - 1] . x;
  4109.             if (atoms[atomSerialNumber - 1] . x > bounds[1]) bounds[1] = atoms[atomSerialNumber - 1] . x;
  4110.             if (atoms[atomSerialNumber - 1] . y < bounds[2]) bounds[2] = atoms[atomSerialNumber - 1] . y;
  4111.             if (atoms[atomSerialNumber - 1] . y > bounds[3]) bounds[3] = atoms[atomSerialNumber - 1] . y;
  4112.             if (atoms[atomSerialNumber - 1] . z < bounds[4]) bounds[4] = atoms[atomSerialNumber - 1] . z;
  4113.             if (atoms[atomSerialNumber - 1] . z > bounds[5]) bounds[5] = atoms[atomSerialNumber - 1] . z;
  4114.  
  4115.             /*Get the residue number*/
  4116.             if (GetFLong(&(atoms[atomSerialNumber - 1] . residue), tempStr, 23,26))
  4117.             {
  4118.             if (atoms[atomSerialNumber - 1] . residue > topResidue)
  4119.             {
  4120.                 topResidue = atoms[atomSerialNumber - 1] . residue;
  4121.             }
  4122.             if (atoms[atomSerialNumber - 1] . residue < topResidue)
  4123.             {
  4124.                 /*DIKEO residue out of order, do something?*/ 
  4125.             }
  4126.             }
  4127.  
  4128.             /*Try to figure out the name of the atom*/
  4129.             atoms[atomSerialNumber - 1] . atomicNumber = 
  4130.             atomicNumber = getAtomNum(tempStr, &atomRemoteness);
  4131.  
  4132.             isCarbonAlpha = false;
  4133.             if (atomicNumber == 6)
  4134.             {
  4135.             /*It's carbon, may be an alpha carbon*/
  4136.             if (atomRemoteness == 'A')
  4137.             {
  4138.                 isCarbonAlpha = true;
  4139.             }
  4140.             }
  4141.             atoms[atomSerialNumber - 1] . isCarbonAlpha = isCarbonAlpha;
  4142.  
  4143.             /*Get the occupancy and temperature factor*/
  4144.             if (!GetFReal(&(atoms[atomSerialNumber - 1] . occupancy), tempStr, 55, 60))
  4145.             {
  4146.             atoms[atomSerialNumber - 1] . occupancy = missingData;
  4147.             }
  4148.             if (!GetFReal(&(atoms[atomSerialNumber - 1] . tempFactor), tempStr, 61, 66))
  4149.             {
  4150.             atoms[atomSerialNumber - 1] . tempFactor = missingData;
  4151.             }
  4152.         }
  4153.         else if (0 == strcmp2("REMARK", typeBuf))
  4154.         {
  4155.             if (!remark)
  4156.             {
  4157.             remark = NewTextBuf();
  4158.             }
  4159.             GetFString(noteBuf, tempStr, 12, 70);
  4160.             SmartAppendTextLine(remark, noteBuf);
  4161.         }
  4162.         else if (0 == strcmp2("SOURCE", typeBuf))
  4163.         {
  4164.             if (!source)
  4165.             {
  4166.             source = NewTextBuf();
  4167.             }
  4168.             GetFString(noteBuf, tempStr, 11, 70);
  4169.             SmartAppendTextLine(source, noteBuf);
  4170.         }
  4171.         else if (0 == strcmp2("AUTHOR", typeBuf))
  4172.         {
  4173.             if (!author)
  4174.             {
  4175.             author = NewTextBuf();
  4176.             }
  4177.             GetFString(noteBuf, tempStr, 11, 70);
  4178.             SmartAppendTextLine(author, noteBuf);
  4179.         }
  4180.         else if (0 == strcmp2("EXPDTA", typeBuf))
  4181.         {
  4182.             if (!expData)
  4183.             {
  4184.             expData = NewTextBuf();
  4185.             }
  4186.             GetFString(noteBuf, tempStr, 11, 70);
  4187.             SmartAppendTextLine(expData, noteBuf);
  4188.         }
  4189.         else if (0 == strcmp2("JRNL  ", typeBuf))
  4190.         {
  4191.             if (!journal)
  4192.             {
  4193.             journal = NewTextBuf();
  4194.             }
  4195.             GetFString(noteBuf, tempStr, 11, 70);
  4196.             SmartAppendTextLine(journal, noteBuf);
  4197.         }
  4198.         else if (0 == strcmp2("COMPND", typeBuf) && !nameGiven)
  4199.         {
  4200.             /*Extract a reasonable compound name from the line*/
  4201.             GetFString(compoundName, tempStr, 11, 70);
  4202.             nameGiven = true;
  4203.         }
  4204.         else if (0 == strcmp2("CONECT", typeBuf))
  4205.         {
  4206.             /*Connectivity*/
  4207.             long thisAtom, otherAtom;
  4208.  
  4209.             /*See what this atom is*/
  4210.             if (!GetFLong(&thisAtom, tempStr, 7, 11))
  4211.             {
  4212.             continue;
  4213.             }
  4214.  
  4215.             /*Check all the bonds*/
  4216.             if (GetFLong(&otherAtom, tempStr, 12, 16))
  4217.             {
  4218.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4219.             }
  4220.             if (GetFLong(&otherAtom, tempStr, 17, 21))
  4221.             {
  4222.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4223.             }
  4224.             if (GetFLong(&otherAtom, tempStr, 22, 26))
  4225.             {
  4226.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4227.             }
  4228.             if (GetFLong(&otherAtom, tempStr, 27, 31))
  4229.             {
  4230.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4231.             }
  4232.             if (GetFLong(&otherAtom, tempStr, 32, 36))
  4233.             {
  4234.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4235.             }
  4236.             if (GetFLong(&otherAtom, tempStr, 37, 41))
  4237.             {
  4238.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4239.             }
  4240.             if (GetFLong(&otherAtom, tempStr, 42, 46))
  4241.             {
  4242.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4243.             }
  4244.             if (GetFLong(&otherAtom, tempStr, 47, 51))
  4245.             {
  4246.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4247.             }
  4248.             if (GetFLong(&otherAtom, tempStr, 52, 56))
  4249.             {
  4250.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4251.             }
  4252.             if (GetFLong(&otherAtom, tempStr, 57, 61))
  4253.             {
  4254.             MAKEBOND(thisAtom - 1, otherAtom - 1);
  4255.             }
  4256.         }
  4257.         }
  4258.     }
  4259.     fclose(inFile);
  4260.  
  4261.     /*Make the notes*/
  4262.     notes = NewList();
  4263.     if (source)
  4264.     {
  4265.         PostfixList(notes, NewString("Source"));
  4266.         PostfixList(notes, NewString(GetBuiltText(source)));
  4267.         DisposeTextBuf(source);
  4268.     }
  4269.     if (expData)
  4270.     {
  4271.         PostfixList(notes, NewString("Exp. Data"));
  4272.         PostfixList(notes, NewString(GetBuiltText(expData)));
  4273.         DisposeTextBuf(expData);
  4274.     }
  4275.     if (author)
  4276.     {
  4277.         PostfixList(notes, NewString("Author"));
  4278.         PostfixList(notes, NewString(GetBuiltText(author)));
  4279.         DisposeTextBuf(author);
  4280.     }
  4281.     if (journal)
  4282.     {
  4283.         PostfixList(notes, NewString("Journal"));
  4284.         PostfixList(notes, NewString(GetBuiltText(journal)));
  4285.         DisposeTextBuf(journal);
  4286.     }
  4287.     if (remark)
  4288.     {
  4289.         PostfixList(notes, NewString("Remarks"));
  4290.         PostfixList(notes, NewString(GetBuiltText(remark)));
  4291.         DisposeTextBuf(remark);
  4292.     }
  4293.  
  4294.     /*Now maybe there are some atoms*/
  4295.     if (nAtoms)
  4296.     {
  4297.         ObjPtr formVectors, dataForm, occupancyDataset, tempFactorDataset,
  4298.            atomicNumberDataset, radiusDataset; 
  4299.         char *s, *t;
  4300.         ObjPtr timeStepDataset;
  4301.         ObjPtr residues;
  4302.         long dims[2];
  4303.  
  4304.         /*Make a reasonable-sounding compound name*/
  4305.         if (!nameGiven)
  4306.         {
  4307.         strcpy(compoundName, GetString(MakeDatasetName(fileName)));
  4308.         }
  4309.  
  4310.         s = compoundName;
  4311.         SKIPBLANKS(s);
  4312.         if (!s)
  4313.         {
  4314.         strcpy(compoundName, GetString(MakeDatasetName(fileName)));
  4315.         s = compoundName;
  4316.         }
  4317.  
  4318.         t = s;
  4319.         /*Go until end of string or until first (*/
  4320.         while (*t && *t != '(') ++t;
  4321.         --t;
  4322.  
  4323.         /*Back up until last non-blank char*/
  4324.         while (isspace(*t)) --t;
  4325.  
  4326.         /*Advance one and plop a 0*/
  4327.         ++t;
  4328.         *t = 0;
  4329.  
  4330.         /*Capitalize the compound name like a title*/
  4331.         Titleize(s);
  4332.  
  4333.         /*Make a vector dataset for the form*/
  4334.         formVectors = NewDataset("form vectors", 1, &nAtoms, 3);
  4335.  
  4336.         /*Make datasets*/
  4337.         strcpy(t, " Occupancy");
  4338.         occupancyDataset = NewDataset(s, 1, &nAtoms, 0);
  4339.         SetVar(occupancyDataset, NOTES, notes);
  4340.  
  4341.         strcpy(t, " Temp Factor");
  4342.         tempFactorDataset = NewDataset(s, 1, &nAtoms, 0);
  4343.         SetVar(tempFactorDataset, NOTES, notes);
  4344.  
  4345.         strcpy(t, " Atoms");
  4346.         atomicNumberDataset = NewDataset(s, 1, &nAtoms, 0);
  4347.         SetVar(atomicNumberDataset, NOTES, notes);
  4348.         SetVar(atomicNumberDataset, UNITSNAME, NewString("Atomic number"));
  4349.  
  4350.         strcpy(t, " Radii");
  4351.         radiusDataset = NewDataset(s, 1, &nAtoms, 0);
  4352.         SetVar(radiusDataset, NOTES, notes);
  4353.  
  4354.         /*Fill it all up*/
  4355.         SetCurField(FORMFIELD, formVectors);
  4356.         SetCurField(FIELD1, occupancyDataset);
  4357.         SetCurField(FIELD2, tempFactorDataset);
  4358.         SetCurField(FIELD3, atomicNumberDataset);
  4359.         SetCurField(FIELD4, radiusDataset);
  4360.  
  4361.         /*Fill fields with atoms.*/
  4362.         for (k = 0; k < nAtoms; ++k)
  4363.         {
  4364.         PutFieldComponent(FORMFIELD, 0, &k, atoms[k] . x);
  4365.         PutFieldComponent(FORMFIELD, 1, &k, atoms[k] . y);
  4366.         PutFieldComponent(FORMFIELD, 2, &k, atoms[k] . z);
  4367.         PutFieldComponent(FIELD1, 0, &k, atoms[k] . occupancy);
  4368.         PutFieldComponent(FIELD2, 0, &k, atoms[k] . tempFactor);
  4369.         PutFieldComponent(FIELD3, 0, &k, 
  4370.             atoms[k] . atomicNumber ? (real) atoms[k] . atomicNumber : missingData);
  4371.         PutFieldComponent(FIELD4, 0, &k, 
  4372.             atoms[k] . atomicNumber ? atomInfo[atoms[k] . atomicNumber - 1] . radius : missingData);
  4373.         }
  4374.  
  4375.         if (!nBonds)
  4376.         {
  4377. #ifndef RELEASE
  4378.         /*Get bonds*/
  4379.         strcpy(tempStr, fileName);
  4380.         strcat(tempStr, ".con");
  4381.  
  4382.         if (inFile = fopen(tempStr, "r"))
  4383.         {
  4384.         /*Read in bonds*/
  4385.         int k, l;
  4386.  
  4387.         nBonds = 0;
  4388.         nBondsAllocated = 200;
  4389.         bondsBuffer = (TwoReals *) Alloc(sizeof(TwoReals) * nBondsAllocated);
  4390.         while (2 == fscanf(inFile, " %d %d", &k, &l))
  4391.         {
  4392.             if (nBonds >= nBondsAllocated)
  4393.             {
  4394.             nBondsAllocated += 200;
  4395.             bondsBuffer = (TwoReals *) Realloc(bondsBuffer,
  4396.                 sizeof(TwoReals) * nBondsAllocated);
  4397.             }
  4398.             bondsBuffer[nBonds][0] = k - 1;
  4399.             bondsBuffer[nBonds][1] = l - 1;
  4400.             ++nBonds;
  4401.         }
  4402.         }
  4403.         else
  4404. #endif
  4405.         {
  4406.         /*Try to guess some bonds*/
  4407.         printf("Guessing bonds\n");
  4408.         nBonds = 0;
  4409.         nBondsAllocated = 200;
  4410.         bondsBuffer = (TwoReals *) Alloc(sizeof(TwoReals) * nBondsAllocated);
  4411.         for (k = 0; k < nAtoms; ++k)
  4412.         {
  4413.             long l;
  4414.             real d2, maxd;
  4415.             maxd = SQUARE(2.0);
  4416.     
  4417.             /*Only search atoms within 10*/
  4418.             for (l = k + 1; l < MAX(nAtoms, k + 20); ++l)
  4419.             {
  4420.             d2 = SQUARE(atoms[k] . x - atoms[l] . x) +
  4421.                  SQUARE(atoms[k] . y - atoms[l] . y) +
  4422.                  SQUARE(atoms[k] . z - atoms[l] . z);
  4423.             if (d2 < maxd)
  4424.             {
  4425.                 if (nBonds >= nBondsAllocated)
  4426.                 {
  4427.                 nBondsAllocated += 200;
  4428.                 bondsBuffer = (TwoReals *) Realloc(bondsBuffer,
  4429.                     sizeof(TwoReals) * nBondsAllocated);
  4430.                 }
  4431.                 bondsBuffer[nBonds][0] = k;
  4432.                 bondsBuffer[nBonds][1] = l;
  4433.                 ++nBonds;
  4434.             }
  4435.             }
  4436.         }
  4437.         }
  4438.         }
  4439.  
  4440.  
  4441.         dims[0] = nAtoms;
  4442.         dims[1] = nBonds;
  4443.         dataForm = NewUnstructuredDataForm("form", 1, dims, bounds, formVectors);
  4444.         if (nBonds)
  4445.         {
  4446.         /*Set the bonds*/
  4447.         for (k = 0; k < nBonds; ++k)
  4448.         {
  4449.             Put1Edge(dataForm, k,
  4450.             (long) bondsBuffer[k][0], (long) bondsBuffer[k][1]);
  4451.         }
  4452.         }
  4453.  
  4454.         SetDatasetForm(occupancyDataset, dataForm);
  4455.         SetDatasetForm(tempFactorDataset, dataForm);
  4456.         SetDatasetForm(atomicNumberDataset, dataForm);
  4457.         SetDatasetForm(radiusDataset, dataForm);
  4458.  
  4459.         /*Make carbon alpha edges*/
  4460.         residues = NewRealArray(2, topResidue, 2L);
  4461.         if (residues)
  4462.         {
  4463.         TwoReals *residueElements;
  4464.         int curResidue;
  4465.         int residueBeginning;
  4466.         int i;
  4467.         int alphaCarbon;
  4468.         
  4469.  
  4470.         residueElements = (TwoReals *) ELEMENTS(residues);
  4471.  
  4472.         curResidue = 1;        /*In file, residues begin at 1*/
  4473.         alphaCarbon = -1;    /*No alpha carbon yet*/
  4474.         residueBeginning = 0;
  4475.         for (k = 0; k <= nAtoms; ++k)
  4476.         {
  4477.             if (atoms[k] . atomicNumber > 0)
  4478.             {
  4479.             if (k == nAtoms || atoms[k] . residue > curResidue)
  4480.             {
  4481.             /*Have to finish up this residue*/
  4482.             residueElements[curResidue - 1][0] = (real) k - 1;
  4483.  
  4484.             if (alphaCarbon >= 0)
  4485.             {
  4486.                 /*Set this to the alpha carbon*/
  4487.             }
  4488.             else
  4489.             {
  4490.                 /*Guess an alpha carbon, pick the first carbon*/
  4491.                 for (i = residueBeginning; i < k; ++i)
  4492.                 {
  4493.                 if (atoms[i] . atomicNumber == 6)
  4494.                 {
  4495.                     alphaCarbon = i;
  4496.                     break;
  4497.                 }
  4498.                 }
  4499.  
  4500.                 /*If there Still isn't an alpha carbon, pick middle*/
  4501.                 if (alphaCarbon < 0)
  4502.                 {
  4503.                 alphaCarbon = (i + k - 1) / 2;
  4504.                 }
  4505.             }
  4506.             residueElements[curResidue - 1][1] = (real) alphaCarbon;
  4507.             alphaCarbon = -1;
  4508.             residueBeginning = k;
  4509.             if (k < nAtoms)
  4510.             {
  4511.                 curResidue = atoms[k] . residue;
  4512.             }
  4513.             }
  4514.             if (k < nAtoms)
  4515.             {
  4516.             /*Still more to go*/
  4517.             if (atoms[k] . isCarbonAlpha)
  4518.             {
  4519.                 alphaCarbon = k;
  4520.             }
  4521.             }
  4522.             }
  4523.         }
  4524.         
  4525.         SetVar(dataForm, RESIDUES, residues);
  4526.         }
  4527.  
  4528.         SetVar(atomicNumberDataset, SIZEOBJ, radiusDataset);
  4529.         SetVar(occupancyDataset, SIZEOBJ, radiusDataset);
  4530.         SetVar(tempFactorDataset, SIZEOBJ, radiusDataset);
  4531.         SetVar(radiusDataset, SIZEOBJ, radiusDataset);
  4532.  
  4533.         RegisterNewDataset(atomicNumberDataset);
  4534.         RegisterNewDataset(occupancyDataset);
  4535.         RegisterNewDataset(tempFactorDataset);
  4536.         RegisterNewDataset(radiusDataset);
  4537.  
  4538. #ifndef RELEASE
  4539. #ifdef WIGGLY
  4540.         /*Make wiggly bits*/
  4541.         SetMethod(formVectors, MARKTIME, FiddleData);
  4542.         DeferMessage(formVectors, MARKTIME);
  4543.         SetMethod(formVectors, DATA, MakeWigglyMoleculeCurData);
  4544. #else
  4545. #ifdef SHMDIDDLE
  4546.         timeStepDataset = NewDataset("Duration (ps)", 0, &nAtoms, 0);
  4547.         RegisterDataset(timeStepDataset);    
  4548.         /*Set up to diddle with shared memory*/
  4549.         if (0 == sharedSegment)
  4550.         {
  4551.         /*Make a new piece of shared memory*/
  4552.         key_t key;
  4553.         long size;
  4554.  
  4555.         size = 1 + nAtoms * 3;
  4556.  
  4557.         key = ftok(fileName, 37);
  4558.         if (key > 0)
  4559.         {
  4560.             /*Key OK, make an ID*/
  4561.             int shmid;
  4562.             printf("fileName = %s, key = %d, size = %d\n", fileName, key,
  4563.                 sizeof(real) * (1 + nAtoms * 3));
  4564.             shmid = shmget(key, sizeof(real) * (1 + nAtoms * 3), IPC_CREAT);
  4565.             if (shmid > 0)
  4566.             {
  4567.             /*Key ok, make shared memory segment*/
  4568.             sharedSegment = (real *) shmat(shmid, (void *) 0, 0);
  4569.             if (((long) sharedSegment) > 0)
  4570.             {
  4571.  
  4572.  
  4573.                 /*It's OK, let's do it.*/
  4574.                 *sharedSegment = 0.0;
  4575.                 SetVar(formVectors, SHMSEMAPHORE, NewReal(0.0));
  4576.                 SetVar(formVectors, SHMADDRESS, NewInt((int) sharedSegment));
  4577.  
  4578.                 SetVar(timeStepDataset, SHMSEMAPHORE, NewReal(0.0));
  4579.                 SetVar(timeStepDataset, SHMADDRESS, NewInt((int) sharedSegment));
  4580.  
  4581.                 /*Make initial setup*/
  4582.                 sharedSegment[1] = (real) nAtoms;
  4583.                 for (k = 0; k < nAtoms; ++k)
  4584.                 {
  4585.                 sharedSegment[1 + k * 3] = atoms[k] . x;
  4586.                 sharedSegment[2 + k * 3] = atoms[k] . y;
  4587.                 sharedSegment[3 + k * 3] = atoms[k] . z;
  4588.                 }
  4589.  
  4590.                 SetMethod(formVectors, MARKTIME, DiddleData);
  4591.                 DeferMessage(formVectors, MARKTIME);
  4592.                 SetMethod(timeStepDataset, MARKTIME, DiddleTimestep);
  4593.                 DeferMessage(timeStepDataset, MARKTIME);
  4594.             }
  4595.             else
  4596.             {
  4597.                 perror("can't attach segment");
  4598.             }
  4599.             }
  4600.             else
  4601.             {
  4602.             printf("%d is a ", shmid);
  4603.             perror("bad shared memory id");
  4604.             }
  4605.         }
  4606.         else
  4607.         {
  4608.             perror("bad key");
  4609.         }
  4610.         }
  4611. #endif
  4612. #endif
  4613. #endif
  4614.     }
  4615.  
  4616.     SAFEFREE(bondsBuffer);
  4617.     SAFEFREE(atoms);
  4618.  
  4619.     return ObjTrue;
  4620.     }
  4621.     else
  4622.     {
  4623.     sprintf(tempStr, "File %s cannot be opened.", fileName);
  4624.     FileFormatError("ReadPDBFile", tempStr);
  4625.     return ObjFalse;
  4626.     }
  4627. }
  4628.  
  4629. static ObjPtr ReadGTFile(fileName)
  4630. char *fileName;
  4631. /*Reads a geometry test file.*/
  4632. {
  4633.     ObjPtr dataForm = NULLOBJ;        /*Data form*/
  4634.     ObjPtr dataFormData = NULLOBJ;    /*Data form*/
  4635.     ObjPtr normalsData = NULLOBJ;    /*Normals*/
  4636.     ObjPtr geometryDataset = NULLOBJ;    /*Geometry dataset*/
  4637.     ObjPtr scalarDatasets = NULLOBJ;
  4638.     ThingListPtr runner;
  4639.     real bounds[6];
  4640.     long polygonVertices[100];
  4641.     char keyword[100];
  4642.     long size = 1;
  4643.     long nVertices = 0;
  4644.     long vertex;
  4645.     long n;
  4646.     long k;
  4647.     float x, y, z;
  4648.     FILE *inFile;
  4649.  
  4650.     inFile = fopen(fileName, "r");
  4651.     if (inFile)
  4652.     {
  4653.     scalarDatasets = NewList();
  4654.     while (1 == fscanf(inFile, " %s", keyword))
  4655.     {
  4656.         if (0 == strcmp(keyword, "VERTICES"))
  4657.         {
  4658.         if (1 != fscanf(inFile, " %ld \n", &size))
  4659.         {
  4660.             FileFormatError("ReadGTFile", "# vertices expected");
  4661.             return NULLOBJ;
  4662.         }
  4663.  
  4664.         /*Create a new dataform dataset*/
  4665.         dataFormData = NewDataset("geometry vertices data", 1, &size, 3);
  4666.         SetCurField(FIELD1, dataFormData);
  4667.         bounds[0] = bounds[2] = bounds[4] = plusInf;
  4668.         bounds[1] = bounds[3] = bounds[5] = minusInf;
  4669.         for (k = 0; k < size; ++k)
  4670.         {
  4671.             if (3 != fscanf(inFile, "%g %g %g \n", &x, &y, &z))
  4672.             {
  4673.             FileFormatError("ReadGTFile", "Vertices expected");
  4674.             return NULLOBJ;
  4675.             }
  4676.             PutFieldComponent(FIELD1, 0, &k, x);
  4677.             PutFieldComponent(FIELD1, 1, &k, y);
  4678.             PutFieldComponent(FIELD1, 2, &k, z);
  4679.             bounds[0] = MIN(bounds[0], x);
  4680.             bounds[1] = MAX(bounds[1], x);
  4681.             bounds[2] = MIN(bounds[2], y);
  4682.             bounds[3] = MAX(bounds[3], y);
  4683.             bounds[4] = MIN(bounds[4], z);
  4684.             bounds[5] = MAX(bounds[5], z);
  4685.         }
  4686.  
  4687.         /*Create the dataform*/
  4688.         dataForm = NewUnstructuredDataForm("geometry vertices", 1, &size, bounds, dataFormData);
  4689.         }
  4690.         else if (0 == strcmp(keyword, "NORMALS"))
  4691.         {
  4692.         if (1 != fscanf(inFile, " %ld \n", &size))
  4693.         {
  4694.             FileFormatError("ReadGTFile", "# normals expected");
  4695.             return NULLOBJ;
  4696.         }
  4697.  
  4698.         /*Create a new dataform dataset*/
  4699.         normalsData = NewDataset("geometry vertices data", 1, &size, 3);
  4700.         SetCurField(FIELD1, normalsData);
  4701.         bounds[0] = bounds[2] = bounds[4] = plusInf;
  4702.         bounds[1] = bounds[3] = bounds[5] = minusInf;
  4703.         for (k = 0; k < size; ++k)
  4704.         {
  4705.             if (3 != fscanf(inFile, "%g %g %g \n", &x, &y, &z))
  4706.             {
  4707.             FileFormatError("ReadGTFile", "Vertices expected");
  4708.             return NULLOBJ;
  4709.             }
  4710.             PutFieldComponent(FIELD1, 0, &k, x);
  4711.             PutFieldComponent(FIELD1, 1, &k, y);
  4712.             PutFieldComponent(FIELD1, 2, &k, z);
  4713.             bounds[0] = MIN(bounds[0], x);
  4714.             bounds[1] = MAX(bounds[1], x);
  4715.             bounds[2] = MIN(bounds[2], y);
  4716.             bounds[3] = MAX(bounds[3], y);
  4717.             bounds[4] = MIN(bounds[4], z);
  4718.             bounds[5] = MAX(bounds[5], z);
  4719.         }
  4720.         }
  4721.         else if (0 == strcmp(keyword, "SCALAR"))
  4722.         {
  4723.         ObjPtr tempData;
  4724.         if (1 != fscanf(inFile, " %s \n", &keyword))
  4725.         {
  4726.             FileFormatError("ReadGTFile", "dataset name expected");
  4727.             return NULLOBJ;
  4728.         }
  4729.         if (size < 2)
  4730.         {
  4731.             FileFormatError("ReadGTFile", "scalar values only after vertices");
  4732.             return NULLOBJ;
  4733.         }
  4734.  
  4735.         /*Create a new temporary dataset*/
  4736.         tempData = NewDataset(keyword, 1, &size, 0);
  4737.         SetCurField(FIELD1, tempData);
  4738.         for (k = 0; k < size; ++k)
  4739.         {
  4740.             if (1 != fscanf(inFile, " %g \n", &x))
  4741.             {
  4742.             FileFormatError("ReadGTFile", "Vertices expected");
  4743.             return NULLOBJ;
  4744.             }
  4745.             PutFieldComponent(FIELD1, 0, &k, x);
  4746.         }
  4747.         PrefixList(scalarDatasets, tempData);
  4748.         }
  4749.         else if (0 == strcmp(keyword, "POLYGON"))
  4750.         {
  4751.         if (!geometryDataset)
  4752.         {
  4753.             geometryDataset = NewGeometryDataset("geometry");
  4754.         }
  4755.         if (1 != fscanf(inFile, " %ld \n", &nVertices))
  4756.         {
  4757.             FileFormatError("ReadGTFile", "# poly vertices expected");
  4758.             return NULLOBJ;
  4759.         }
  4760.         for (k = 0; k < nVertices; ++k)
  4761.         {
  4762.             if (1 != fscanf(inFile, " %ld \n", &vertex))
  4763.             {
  4764.             FileFormatError("ReadGTFile", "Poly vertex expected");
  4765.             return NULLOBJ;
  4766.             }
  4767.             if (k < 100) polygonVertices[k] = vertex;
  4768.         }
  4769.         AppendPolygonToDataset(geometryDataset, MIN(nVertices, 100), polygonVertices);
  4770.         }
  4771.         else
  4772.         {
  4773.         sprintf(tempStr, "Bad keyword: '%s'", keyword);
  4774.         FileFormatError("ReadGTFile", tempStr);
  4775.         }
  4776.     }
  4777.     if (!feof(inFile))
  4778.     {
  4779.         FileFormatError("ReadGTFile", "Not all of the file was read");
  4780.     }
  4781.     fclose(inFile);
  4782.  
  4783.     if (dataForm)
  4784.     {
  4785.         if (normalsData)
  4786.         {
  4787.         SetDatasetForm(normalsData, dataForm);
  4788.         if (geometryDataset)
  4789.         {
  4790.             SetVar(geometryDataset, NORMALSOBJ, normalsData);
  4791.         }
  4792.         }
  4793.  
  4794.         if (geometryDataset && dataForm)
  4795.         {
  4796.         SetDatasetForm(geometryDataset, dataForm);
  4797.         RegisterNewDataset(geometryDataset);
  4798.         }
  4799.  
  4800.         if (scalarDatasets)
  4801.         {
  4802.         runner = LISTOF(scalarDatasets);
  4803.         while (runner)
  4804.         {
  4805.             SetDatasetForm(runner -> thing, dataForm);
  4806.             RegisterNewDataset(runner -> thing);
  4807.             runner = runner -> next;
  4808.         }
  4809.         }
  4810.     }
  4811.     }
  4812.     else
  4813.     {
  4814.     sprintf(tempStr, "File %s cannot be opened.", fileName);
  4815.     FileFormatError("ReadGTFile", tempStr);
  4816.     return ObjFalse;
  4817.     }    
  4818. }
  4819.  
  4820. void InitFiles(void)
  4821. /*Initializes the file handling routines*/
  4822. {
  4823.     ObjPtr icon, fileReader;
  4824.  
  4825.     fileReaderClass = NewObject(NULLOBJ, 0);
  4826.     AddToReferenceList(fileReaderClass);
  4827.     SetMethod(fileReaderClass, READALL, ReadOldFile);
  4828.     SetMethod(fileReaderClass, NEWCTLWINDOW, ShowFileReaderControls);
  4829.     icon = NewIcon(0, 0, ICONFILEREADER, "?");
  4830.     SetVar(icon, ICONLOC, NULLOBJ);
  4831.     SetVar(icon, FORMAT, NewString("File Reader"));
  4832.     SetVar(fileReaderClass, DEFAULTICON, icon);
  4833.     SetVar(fileReaderClass, SAVEEXTENSION, NewString("filrdr"));
  4834.     SetVar(fileReaderClass, TIMEDDATASETS, ObjTrue);
  4835.     SetMethod(fileReaderClass, SHOWCONTROLS, NewControlWindow);
  4836.     SetVar(fileReaderClass, DOUBLECLICK, NewString(OF_SHOW_CONTROLS));
  4837.     SetVar(fileReaderClass, CLASSID, NewInt(CLASS_FILEREADER));
  4838.     SetMethod(icon, MAKE1HELPSTRING, MakeReaderIconHelp);
  4839.     AddSnapVar(fileReaderClass, EXTENSION);
  4840.     AddSnapVar(fileReaderClass, TIMEDDATASETS);
  4841.     SetMethod(fileReaderClass, SAVECPANEL, SaveSnapshotControls);
  4842.     SetMethod(fileReaderClass, SAVEALLCONTROLS, LogSnapshotControls);
  4843.  
  4844. #ifndef RELEASE
  4845.     DefineFormat("DD", "dd", ReadDDFile, 0);
  4846.     DefineFormat("DD2", "dd2", ReadDD2File, 0);
  4847. #endif
  4848.     DefineFormat("NFF", "nff", ReadNFFXFile, 0);
  4849.     DefineFormat("SY", "sy", ReadSYFile, 0);
  4850. #ifndef RELEASE
  4851.     DefineFormat("GT", "gt", ReadGTFile, 0);
  4852. #endif
  4853. #ifdef LORENZ
  4854.     DefineFormat("LRZ", "lrz", ReadLRZFile, 0);
  4855. #endif
  4856.  
  4857. #ifdef HDFDEF
  4858.  
  4859.     fileReader = NewFileReader("HDF");
  4860.     SetVar(fileReader, EXTENSION, NewString("hdf"));
  4861.     SetVar(fileReader, OUTOFBOUNDS, NewInt(0));
  4862.     AddSnapVar(fileReader, OUTOFBOUNDS);
  4863.     SetVar(fileReader, HELPSTRING,
  4864.     NewString("This file reader reads scientific datasets using the HDF data \
  4865. format, developed at the National Center for Supercomputing Applications.  Libraries \
  4866. for reading HDF files and documentation are available via anonymous ftp from \
  4867. ftp.ncsa.uiuc.edu."));
  4868.     SetVar(fileReader, READVECTOR, ObjTrue);
  4869.     AddSnapVar(fileReader, READVECTOR);
  4870.     SetVar(fileReader, WRAPPOLAR, ObjTrue);
  4871.     AddSnapVar(fileReader, WRAPPOLAR);
  4872.     SetVar(fileReader, COMPRESSDATA, ObjFalse);
  4873.     AddSnapVar(fileReader, COMPRESSDATA);
  4874.     SetVar(fileReader, BOTHERWITHAXES, ObjFalse);
  4875.     AddSnapVar(fileReader, BOTHERWITHAXES);
  4876.     SetMethod(fileReader, READALL, ReadHDFFile);
  4877.     SetMethod(fileReader, ADDCONTROLS, AddHDFControls);
  4878.     ApplySavedSettings(fileReader);
  4879.  
  4880. #endif
  4881.  
  4882.     fileReader = NewFileReader("PDB");
  4883.     SetVar(fileReader, EXTENSION, NewString("ent"));
  4884.     SetVar(fileReader, HELPSTRING,
  4885.     NewString("This file reader reads scientific datasets using the Protein \
  4886. Data Bank file format.  Files are read as datasets over unstructured grids."));
  4887.     SetMethod(fileReader, READALL, ReadPDBFile);
  4888.     ApplySavedSettings(fileReader);
  4889.  
  4890. #ifndef RELEASE
  4891.     DefineFormat("JAK", "", ReadJAKFile, 0);
  4892.     DefineFormat("JAKB", "", ReadJAKBFile, 0);
  4893. #endif
  4894.     fileClass = NewObject(NULLOBJ, 0);
  4895.     AddToReferenceList(fileClass);
  4896.     SetVar(fileClass, CLASSID, NewInt(CLASS_FILE));
  4897.     InitHwuFiles();
  4898.     InitWhisselFiles();
  4899. #ifdef NETCDFDEF
  4900.     InitGaryFiles();
  4901. #endif
  4902. #ifdef JERRYFILES
  4903.     InitJerryFiles();
  4904. #endif
  4905.     InitSIMSFiles();
  4906.     InitFileSystem();
  4907. }
  4908.  
  4909. void KillFiles(void)
  4910. /*Kills the file handling routines*/
  4911. {
  4912.     int k;
  4913.  
  4914. #ifdef SHMDIDDLE
  4915.     if (sharedSegment)
  4916.     {
  4917.     shmdt(sharedSegment);
  4918.     }
  4919. #endif
  4920.  
  4921. #ifdef JERRYFILES
  4922.     KillJerryFiles();
  4923. #endif
  4924. #ifdef NETCDFDEF
  4925.     KillGaryFiles();
  4926. #endif
  4927.     KillSIMSFiles();
  4928.     KillWhisselFiles();
  4929.     KillHwuFiles();
  4930.     DeleteThing(fileClass);
  4931.     DeleteThing(fileReaderClass);
  4932. }
  4933.